91int main(
int argc,
char *argv[])
97 po::options_description desc(
"Available options");
98 desc.add_options()(
"help,h",
"Produce this help message.")(
99 "verbose,v",
"Turn on verbosity.")(
"generate-metric,g",
100 po::value<vector<int>>(),
101 "Generate a single metric.")(
102 "generate-all-metrics,a",
"Generate all metrics.")(
103 "executable,e", po::value<string>(),
"Use specified executable.");
105 po::options_description hidden(
"Hidden options");
106 hidden.add_options()(
"input-file", po::value<string>(),
"Input filename");
108 po::options_description cmdline_options(
"Command-line options");
109 cmdline_options.add(hidden).add(desc);
111 po::options_description visible(
"Allowed options");
114 po::positional_options_description p;
115 p.add(
"input-file", -1);
117 po::variables_map vm;
121 po::store(po::command_line_parser(argc, argv)
122 .options(cmdline_options)
128 catch (
const exception &e)
130 cerr << e.what() << endl;
135 if (vm.count(
"help") || vm.count(
"input-file") != 1)
137 cerr <<
"Usage: Tester [options] input-file.tst" << endl;
142 bool verbose = vm.count(
"verbose");
145 vector<int> metricGenVec;
146 if (vm.count(
"generate-metric"))
148 metricGenVec = vm[
"generate-metric"].as<vector<int>>();
150 set<int> metricGen(metricGenVec.begin(), metricGenVec.end());
153 const fs::path specFile(vm[
"input-file"].as<string>());
156 fs::path specPath = specFile.parent_path();
158 if (specPath.empty())
160 specPath = fs::current_path();
163 string specFileStem = specFile.stem().string();
167 const fs::path masterDir =
171 const fs::path startDir = fs::current_path();
177 cerr <<
"Reading test file definition: " << specFile << endl;
185 cerr <<
"Creating metrics:" << endl;
189 vector<MetricSharedPtr> metrics;
192 set<int>::iterator it = metricGen.find(file.
GetMetricId(i));
194 it != metricGen.end() || (vm.count(
"generate-all-metrics") > 0);
201 cerr <<
" - ID " << metrics.back()->GetID() <<
": "
202 << metrics.back()->GetType() << endl;
205 if (it != metricGen.end())
211 if (metricGen.size() != 0)
213 string s = metricGen.size() == 1 ?
"s" :
"";
214 set<int>::iterator it;
215 cerr <<
"Unable to find metric" + s +
" with ID" + s +
" ";
216 for (it = metricGen.begin(); it != metricGen.end(); ++it)
225 if (fs::exists(masterDir))
227 fs::remove_all(masterDir);
232 cerr <<
"Creating master directory: " << masterDir << endl;
236 fs::create_directory(masterDir);
239 fs::current_path(masterDir);
243 fstream masterOut(
"master.out", ios::out | ios::in | ios::trunc);
244 fstream masterErr(
"master.err", ios::out | ios::in | ios::trunc);
246 if (masterOut.bad() || masterErr.bad())
248 cerr <<
"One or more master output files are unreadable." << endl;
253 vector<fs::path> tmpWorkingDirs;
256 for (
unsigned int i = 0; i < file.
GetNumRuns(); ++i)
262 cerr <<
"Starting run " << i <<
"." << endl;
266 const fs::path tmpDir =
267 masterDir / fs::path(
"run" + std::to_string(i));
268 tmpWorkingDirs.push_back(tmpDir);
272 cerr <<
"Creating working directory: " << tmpDir << endl;
276 fs::create_directory(tmpDir);
279 fs::current_path(tmpDir);
283 cerr <<
"Copying required files: " << endl;
292 fs::path source = specPath / source_file;
293 fs::path dest = tmpDir / source_file.filename();
296 cerr <<
" - " << source <<
" -> " << dest << endl;
299 if (fs::is_directory(source))
301 fs::create_directory(dest);
304 for (
const auto &dirEnt :
305 fs::recursive_directory_iterator{source})
307 fs::path newdest = dest / dirEnt.path().filename();
308 fs::copy_file(dirEnt.path(), newdest);
313 fs::copy_file(source, dest);
318 fs::path source_file(
"test.opt");
319 fs::path source = specPath / source_file;
320 bool HaveOptFile =
false;
321 if (fs::exists(source))
323 fs::path dest = tmpDir / source_file.filename();
326 cerr <<
" - " << source <<
" -> " << dest << endl;
329 if (fs::is_directory(source))
331 fs::create_directory(dest);
334 for (
const auto &dirEnt :
335 fs::recursive_directory_iterator{source})
337 fs::path newdest = dest / dirEnt.path().filename();
338 fs::copy_file(dirEnt.path(), newdest);
343 fs::copy_file(source, dest);
353 setenv(
"PYTHONPATH",
"@NEKPY_BASE_DIR@",
true);
358 bool mpiAdded =
false;
363#ifdef NEKTAR_TEST_FORCEMPIEXEC
374 command +=
"\"@MPIEXEC@\" ";
375 if (std::string(
"@NEKTAR_TEST_USE_HOSTFILE@") ==
"ON")
377 command +=
"-hostfile hostfile ";
378#if (NEKTAR_MPI_TYPE == 1)
379 if (system(
"echo 'localhost:12' > hostfile"))
381 if (system(
"echo 'localhost slots=12' > hostfile"))
384 cerr <<
"Unable to write 'hostfile' in path '"
385 << fs::current_path() << endl;
392#if (NEKTAR_MPI_TYPE == 1)
400 command +=
"--tag-output ";
424 command +=
"\"@MPIEXEC@\" ";
425 if (std::string(
"@NEKTAR_TEST_USE_HOSTFILE@") ==
"ON")
427 command +=
"-hostfile hostfile ";
436 command +=
"@MPIEXEC_NUMPROC_FLAG@ ";
442 if (!fs::exists(execPath))
452 command +=
"@Python3_EXECUTABLE@ ";
456 command += pathString;
459 command +=
" --use-opt-file test.opt ";
464 command +=
" 1>output.out 2>output.err";
471 cerr <<
"Running command: " << command << endl;
475 if (system(command.c_str()))
477 cerr <<
"Error occurred running test:" << endl;
478 cerr <<
"Command: " << command << endl;
483 if (!(fs::exists(
"output.out") && fs::exists(
"output.err")))
485 cerr <<
"One or more test output files are missing." << endl;
490 ifstream vStdout(
"output.out");
491 ifstream vStderr(
"output.err");
492 if (vStdout.bad() || vStderr.bad())
494 cerr <<
"One or more test output files are unreadable." << endl;
501 cerr <<
"Appending run " << i <<
" output and error to master."
505 while (getline(vStdout, line))
507 masterOut << line << endl;
510 while (getline(vStderr, line))
512 masterErr << line << endl;
520 for (
int i = 0; i < metrics.size(); ++i)
522 if (!metrics[i]->SupportsAverage() && file.
GetNumRuns() > 1)
524 cerr <<
"WARNING: Metric " << metrics[i]->GetType()
525 <<
" does not support multiple runs. Test may yield "
526 "unexpected results."
534 if (verbose && metrics.size())
536 cerr <<
"Checking metrics:" << endl;
539 for (
int i = 0; i < metrics.size(); ++i)
542 metricGen.find(metrics[i]->GetID()) != metricGen.end() ||
543 (vm.count(
"generate-all-metrics") > 0);
547 masterOut.seekg(0, ios::beg);
548 masterErr.seekg(0, ios::beg);
552 cerr <<
" - " << (gen ?
"generating" :
"checking")
553 <<
" metric " << metrics[i]->GetID() <<
" ("
554 << metrics[i]->GetType() <<
")... ";
557 if (!metrics[i]->Test(masterOut, masterErr))
562 cerr <<
"failed!" << endl;
567 cerr <<
"passed" << endl;
574 cerr << endl << endl;
578 if (status == 1 || verbose)
582 masterOut.seekg(0, ios::beg);
583 masterErr.seekg(0, ios::beg);
585 cout <<
"=== Output ===" << endl;
586 while (masterOut.good())
588 getline(masterOut, line);
589 cout << line << endl;
591 cout <<
"=== Errors ===" << endl;
592 while (masterErr.good())
594 getline(masterErr, line);
595 cout << line << endl;
604 fs::current_path(startDir);
608 cerr <<
"Removing working directory" << endl;
621 fs::remove_all(masterDir);
624 catch (
const fs::filesystem_error &e)
626 using namespace std::chrono_literals;
627 std::this_thread::sleep_for(1ms);
631 cout <<
"Locked files encountered. "
632 <<
"Retrying after 1ms..." << endl;
644 if (vm.count(
"generate-metric") > 0 ||
645 vm.count(
"generate-all-metrics") > 0)
653 catch (
const fs::filesystem_error &e)
655 cerr <<
"Filesystem operation error occurred:" << endl;
656 cerr <<
" " << e.what() << endl;
657 cerr <<
" Files left in " << masterDir.string() << endl;
661 cerr <<
"Error occurred during test:" << endl;
662 cerr <<
" " << e.what() << endl;
663 cerr <<
" Files left in " << masterDir.string() << endl;
665 catch (
const std::exception &e)
667 cerr <<
"Unhandled exception during test:" << endl;
668 cerr <<
" " << e.what() << endl;
669 cerr <<
" Files left in " << masterDir.string() << endl;
673 cerr <<
"Unknown error during test" << endl;
674 cerr <<
" Files left in " << masterDir.string() << endl;