IODA Bundle
TestRunner.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 /// \file TestRunner.h
12 ///
13 /// @author Piotr Kuchta, ECMWF, Feb 2009
14 
15 #include <sstream>
16 #include <memory>
17 #include <fstream>
18 
19 #include "eckit/exception/Exceptions.h"
20 #include "eckit/filesystem/PathName.h"
21 #include "eckit/log/Timer.h"
22 #include "eckit/utils/StringTools.h"
23 
24 #include "odc/CommandLineParser.h"
25 #include "odc/tools/Tool.h"
26 #include "odc/tools/TestCase.h"
27 #include "odc/tools/ToolFactory.h"
28 #include "odc/tools/TestRunner.h"
29 
30 using namespace eckit;
31 using namespace std;
32 
33 namespace odc {
34 namespace tool {
35 namespace test {
36 
37 TestRunner::TestRunner (CommandLineParser& clp)
38 : clp_(clp),
39  mars_sms_label_(false),
40  label_()
41 {
42  if (getenv("MARS_SMS_LABEL"))
43  {
44  mars_sms_label_ = true;
45  label_ = getenv("MARS_SMS_LABEL");
46  }
47 }
48 
50 
52 {
53  ASSERT(getenv("odc_TEST_DATA_PATH") && "odc_TEST_DATA_PATH must be set");
54 
55  stringstream totalRunningTime;
56  unique_ptr<Timer> allTestsTimer(new Timer("Total", totalRunningTime));
57  unique_ptr<TestCases> tests;
58 
59  failed_.clear();
60 
61  if (clp_.parameters().size() == 1)
62  {
63  tests.reset(AbstractToolFactory::testCases());
64  Log::info() << "clp_.parameters()" << clp_.parameters() << endl;
65  runTests(*tests);
66  }
67  else
68  {
69  // TODO: keep the config in the odc_TEST_DATA_PATH
70  //readConfig("../../../odc/src/odb/TestRunnerApplication.cfg");
71  readConfig("/tmp/Dropbox/work/odc/src/odb/TestRunnerApplication.cfg");
72  readConfig("/tmp/Dropbox/work/odc/src/tools/TestRunnerApplication.cfg");
73  tests.reset(new TestCases());
74  for (size_t i = 1; i < clp_.parameters().size(); ++i)
75  {
76  string suiteName = clp_.parameters()[i];
77  ASSERT("Suite does not exist" && suites_.find(suiteName) != suites_.end());
78  vector<string>& suite = suites_[suiteName];
79  unique_ptr<vector<TestCase*> > tsts(AbstractToolFactory::testCases(suite));
80 
81  runTests(*tsts);
82  tests->insert(tests->end(), tsts->begin(), tsts->end());
83  }
84  }
85 
86  allTestsTimer.reset();
87 
88  ofstream xmlf("testresults.xml");
89  xmlf << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
90  xmlf << "<testsuite name=\"unittests\" time=\"" << StringTools::split(" ", totalRunningTime.str())[1] << "\">" << endl;
91  xmlf << xml_.str();
92  xmlf << "</testsuite>" << endl;
93 
94  size_t nTests = tests->size();
95  for (size_t i = 0; i < nTests; ++i)
96  delete (*tests)[i];
97 
98  if (failed_.size() == 0) {
99  Log::info() << endl << "+- Phew, made it! All " << nTests << " tests passed successfully. " << endl << endl;
100  Log::info() << runningTimes_.str() << endl;;
101  Log::info() << totalRunningTime.str() << endl;
102  }
103  else
104  {
105  Log::error() << endl << "+- Summary: " << failed_.size() << " test(s) failed." << endl;
106  for (vector<FailedTest>::iterator it = failed_.begin(); it != failed_.end(); ++it) {
107  const string& name = it->first;
108  const string& what = it->second;
109  Log::error() << "\t" << name << ": " << endl << what;
110  }
111  Log::error() << endl;
112 
113  stringstream ss;
114  ss << " " << failed_.size() << " test(s) failed";
115  throw eckit::SeriousBug(ss.str());
116  }
117 }
118 
119 void TestRunner::runTests(const TestCases& tests)
120 {
121  for (TestCases::const_iterator it = tests.begin(); it != tests.end(); ++it)
122  {
123  bool exceptionThrown = false;
124  string what;
125  TestCase *tst = *it;
126  const string& name = tst->name();
127 
128  Log::info() << "+- Running " << name << " ..." << endl;
129  smslabel(name);
130 
131  stringstream runningTime;
132  unique_ptr<Timer> timer(new Timer(name, runningTime));
133  try {
134  tst->setUp();
135  tst->test();
136  } catch (std::exception &e) {
137  Log::warning() << "+- FAILED" << endl;
138  exceptionThrown = true;
139  what += string(e.what()) + '\n';
140  } catch (...) {
141  Log::warning() << "+- FAILED: unknown exception!" << endl;
142  exceptionThrown = true;
143  what += string("Uknown exception") + '\n';
144  }
145  try {
146  tst->tearDown();
147  } catch (std::exception &e) {
148  Log::warning() << "+- Exception thrown from tearDown." << endl;
149  exceptionThrown = true;
150  what += string("[In tearDown:]") + string(e.what()) + '\n';
151  } catch (...) {
152  Log::warning() << "+- FAILED: unknown exception!" << endl;
153  exceptionThrown = true;
154  what += string("Uknown exception") + '\n';
155  }
156 
157  if (exceptionThrown) {
158  failed_.push_back(make_pair(name, what));
159  xml_ << "<testcase classname=\"test\" name=\"" << name << "\">" << endl;
160  xml_ << " <failure type=\"exception\"><![CDATA[" << what << "]]></failure>" << endl;
161  xml_ << "</testcase>" << endl;
162  }
163  else {
164  timer.reset();
165  runningTimes_ << runningTime.str();
166  Log::info() << "+- Passed." << endl << endl;
167  xml_ << "<testcase classname=\"test\" name=\"" << name
168  << "\" time=\"" << StringTools::split(" ", runningTime.str())[1] << "\"/>" << endl;
169  }
170  }
171 }
172 
173 void TestRunner::readConfig(const PathName fileName)
174 {
175  Log::debug() << "TestRunner::readConfig: reading file '" << fileName << "'" << endl;
176  suites_.clear();
177 
178  vector<string> lines = StringTool::readLines(fileName);
179  for (size_t i = 0; i < lines.size(); ++i)
180  {
181  vector<string> words = StringTools::split(":", lines[i]);
182  if (words.size() == 0)
183  continue;
184  ASSERT("Each line of config file should be like: '<suite_name> : TestPattern1 TestPattern2 ...'" && words.size() == 2);
185 
186  suites_[words[0]] = StringTools::split(" \t", words[1]);
187  Log::debug() << "TestRunner::readConfig(\"" << fileName << "\"): "
188  << words[0] << ": "
189  << suites_[words[0]].size() << " entries." << endl;
190  }
191 }
192 
193 void TestRunner::smslabel(const string &s)
194 {
195  if (! mars_sms_label_)
196  return;
197  string cmd = "smslabel ";
198  cmd += label_ + " " + s;
199  system(cmd.c_str());
200 }
201 
202 } // namespace test
203 } // namespace tool
204 } // namespace odc
205 
static std::vector< std::string > readLines(const eckit::PathName fileName, bool logging=false)
Definition: StringTool.cc:34
static std::vector< odc::tool::test::TestCase * > * testCases(const std::vector< std::string > &=matchAll)
Definition: ToolFactory.cc:42
const std::vector< std::string > parameters()
std::string name()
Definition: Tool.h:34
virtual void test()
Definition: TestCase.cc:42
virtual void setUp()
Definition: TestCase.cc:41
virtual void tearDown()
Definition: TestCase.cc:43
void smslabel(const std::string &)
Definition: TestRunner.cc:193
std::stringstream runningTimes_
Definition: TestRunner.h:47
void runTests(const TestCases &tests)
Definition: TestRunner.cc:119
std::stringstream xml_
Definition: TestRunner.h:48
void readConfig(const eckit::PathName fileName)
Definition: TestRunner.cc:173
CommandLineParser clp_
Definition: TestRunner.h:43
std::vector< FailedTest > failed_
Definition: TestRunner.h:46
std::vector< TestCase * > TestCases
Definition: TestCase.h:42
Definition: ColumnInfo.h:23
Definition: encode.cc:30