hdf5/test/API/driver/h5_api_test_driver.cxx
Larry Knox 145e962bce
Replace support.hdfgroup.org URLs for alternative COPYING file (#3228)
* Replace support.hdfgroup.org URLs for alternative COPYING file
locations in copyright headers with https://www.hdfgroup.org/licenses.
Replace  support.hdfgroup.org URL for alternative COPYING_LBNL_HDF5
with github URL.
Tweak chkcopyright script for change from UICOPYRIGHTSTR to
THGCOPYRIGHTSTR.
2023-07-12 17:33:58 -05:00

923 lines
32 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://www.hdfgroup.org/licenses. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "h5_api_test_driver.hxx"
#include "H5_api_test_config.h"
#include <cstdio>
#include <sstream>
#include <iostream>
#include <cstring>
#include <cstdlib>
#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h>
# include <sys/wait.h>
#endif
#include <h5_api_test_sys/RegularExpression.hxx>
#include <h5_api_test_sys/SystemTools.hxx>
using std::vector;
using std::string;
using std::cerr;
// The main function as this class should only be used by this program
int
main(int argc, char *argv[])
{
H5APITestDriver d;
return d.Main(argc, argv);
}
//----------------------------------------------------------------------------
H5APITestDriver::H5APITestDriver()
{
this->ClientArgStart = 0;
this->ClientArgCount = 0;
this->ClientHelperArgStart = 0;
this->ClientHelperArgCount = 0;
this->ClientInitArgStart = 0;
this->ClientInitArgCount = 0;
this->ServerArgStart = 0;
this->ServerArgCount = 0;
this->AllowErrorInOutput = false;
// try to make sure that this times out before dart so it can kill all the processes
this->TimeOut = DART_TESTING_TIMEOUT - 10.0;
this->ServerExitTimeOut = 2; /* 2 seconds timeout for server to exit */
this->ClientHelper = false;
this->ClientInit = false;
this->TestServer = false;
this->TestSerial = false;
this->IgnoreServerResult = false;
}
//----------------------------------------------------------------------------
H5APITestDriver::~H5APITestDriver()
{
}
//----------------------------------------------------------------------------
void
H5APITestDriver::SeparateArguments(const char *str, vector<string> &flags)
{
string arg = str;
string::size_type pos1 = 0;
string::size_type pos2 = arg.find_first_of(" ;");
if (pos2 == arg.npos) {
flags.push_back(str);
return;
}
while (pos2 != arg.npos) {
flags.push_back(arg.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = arg.find_first_of(" ;", pos1 + 1);
}
flags.push_back(arg.substr(pos1, pos2 - pos1));
}
//----------------------------------------------------------------------------
void
H5APITestDriver::CollectConfiguredOptions()
{
if (this->TimeOut < 0)
this->TimeOut = 1500;
#ifdef H5_API_TEST_ENV_VARS
this->SeparateArguments(H5_API_TEST_ENV_VARS, this->ClientEnvVars);
#endif
// now find all the mpi information if mpi run is set
#ifdef MPIEXEC_EXECUTABLE
this->MPIRun = MPIEXEC_EXECUTABLE;
#else
return;
#endif
int maxNumProc = 1;
# ifdef MPIEXEC_MAX_NUMPROCS
if (!this->TestSerial)
maxNumProc = MPIEXEC_MAX_NUMPROCS;
# endif
# ifdef MPIEXEC_NUMPROC_FLAG
this->MPINumProcessFlag = MPIEXEC_NUMPROC_FLAG;
# endif
# ifdef MPIEXEC_PREFLAGS
this->SeparateArguments(MPIEXEC_PREFLAGS, this->MPIClientPreFlags);
# endif
# ifdef MPIEXEC_POSTFLAGS
this->SeparateArguments(MPIEXEC_POSTFLAGS, this->MPIClientPostFlags);
# endif
# ifdef MPIEXEC_SERVER_PREFLAGS
this->SeparateArguments(MPIEXEC_SERVER_PREFLAGS, this->MPIServerPreFlags);
#else
this->MPIServerPreFlags = this->MPIClientPreFlags;
# endif
# ifdef MPIEXEC_SERVER_POSTFLAGS
this->SeparateArguments(MPIEXEC_SERVER_POSTFLAGS, this->MPIServerPostFlags);
#else
this->MPIServerPostFlags = this->MPIClientPostFlags;
# endif
std::stringstream ss;
ss << maxNumProc;
this->MPIServerNumProcessFlag = "1";
this->MPIClientNumProcessFlag = ss.str();
}
//----------------------------------------------------------------------------
/// This adds the debug/build configuration crap for the executable on windows.
static string
FixExecutablePath(const string &path)
{
#ifdef CMAKE_INTDIR
string parent_dir =
h5_api_test_sys::SystemTools::GetFilenamePath(path.c_str());
string filename =
h5_api_test_sys::SystemTools::GetFilenameName(path);
if (!h5_api_test_sys::SystemTools::StringEndsWith(parent_dir.c_str(), CMAKE_INTDIR)) {
parent_dir += "/" CMAKE_INTDIR;
}
return parent_dir + "/" + filename;
#endif
return path;
}
//----------------------------------------------------------------------------
int
H5APITestDriver::ProcessCommandLine(int argc, char *argv[])
{
int *ArgCountP = NULL;
int i;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--client") == 0) {
this->ClientExecutable = ::FixExecutablePath(argv[i + 1]);
++i; /* Skip executable */
this->ClientArgStart = i + 1;
this->ClientArgCount = this->ClientArgStart;
ArgCountP = &this->ClientArgCount;
continue;
}
if (strcmp(argv[i], "--client-helper") == 0) {
std::cerr << "Client Helper" << std::endl;
this->ClientHelper = true;
this->ClientHelperExecutable = ::FixExecutablePath(argv[i + 1]);
++i; /* Skip executable */
this->ClientHelperArgStart = i + 1;
this->ClientHelperArgCount = this->ClientHelperArgStart;
ArgCountP = &this->ClientHelperArgCount;
continue;
}
if (strcmp(argv[i], "--client-init") == 0) {
std::cerr << "Client Init" << std::endl;
this->ClientInit = true;
this->ClientInitExecutable = ::FixExecutablePath(argv[i + 1]);
++i; /* Skip executable */
this->ClientInitArgStart = i + 1;
this->ClientInitArgCount = this->ClientInitArgStart;
ArgCountP = &this->ClientInitArgCount;
continue;
}
if (strcmp(argv[i], "--server") == 0) {
std::cerr << "Test Server" << std::endl;
this->TestServer = true;
this->ServerExecutable = ::FixExecutablePath(argv[i + 1]);
++i; /* Skip executable */
this->ServerArgStart = i + 1;
this->ServerArgCount = this->ServerArgStart;
ArgCountP = &this->ServerArgCount;
continue;
}
if (strcmp(argv[i], "--timeout") == 0) {
this->TimeOut = atoi(argv[i + 1]);
std::cerr << "The timeout was set to " << this->TimeOut << std::endl;
ArgCountP = NULL;
continue;
}
if (strncmp(argv[i], "--allow-errors", strlen("--allow-errors")) == 0) {
this->AllowErrorInOutput = true;
std::cerr << "The allow errors in output flag was set to " <<
this->AllowErrorInOutput << std::endl;
ArgCountP = NULL;
continue;
}
if (strncmp(argv[i], "--allow-server-errors", strlen("--allow-server-errors")) == 0) {
this->IgnoreServerResult = true;
std::cerr << "The allow server errors in output flag was set to " <<
this->IgnoreServerResult << std::endl;
ArgCountP = NULL;
continue;
}
if (strcmp(argv[i], "--serial") == 0) {
this->TestSerial = true;
std::cerr << "This is a serial test" << std::endl;
ArgCountP = NULL;
continue;
}
if (ArgCountP)
(*ArgCountP)++;
}
return 1;
}
//----------------------------------------------------------------------------
void
H5APITestDriver::CreateCommandLine(vector<const char*> &commandLine,
const char *cmd, int isServer, int isHelper, const char *numProc, int argStart,
int argCount, char *argv[])
{
if (!isServer && this->ClientEnvVars.size()) {
for (unsigned int i = 0; i < this->ClientEnvVars.size(); ++i)
commandLine.push_back(this->ClientEnvVars[i].c_str());
#ifdef H5_API_TEST_CLIENT_INIT_TOKEN_VAR
if (this->ClientTokenVar.size())
commandLine.push_back(this->ClientTokenVar.c_str());
#endif
}
if (!isHelper && this->MPIRun.size()) {
commandLine.push_back(this->MPIRun.c_str());
commandLine.push_back(this->MPINumProcessFlag.c_str());
commandLine.push_back(numProc);
if (isServer)
for (unsigned int i = 0; i < this->MPIServerPreFlags.size(); ++i)
commandLine.push_back(this->MPIServerPreFlags[i].c_str());
else
for (unsigned int i = 0; i < this->MPIClientPreFlags.size(); ++i)
commandLine.push_back(this->MPIClientPreFlags[i].c_str());
}
commandLine.push_back(cmd);
if (isServer)
for (unsigned int i = 0; i < this->MPIServerPostFlags.size(); ++i)
commandLine.push_back(MPIServerPostFlags[i].c_str());
else
for (unsigned int i = 0; i < this->MPIClientPostFlags.size(); ++i)
commandLine.push_back(MPIClientPostFlags[i].c_str());
// remaining flags for the test
for (int ii = argStart; ii < argCount; ++ii) {
commandLine.push_back(argv[ii]);
}
commandLine.push_back(0);
}
//----------------------------------------------------------------------------
int
H5APITestDriver::StartServer(h5_api_test_sysProcess *server, const char *name,
vector<char> &out, vector<char> &err)
{
if (!server)
return 1;
cerr << "H5APITestDriver: starting process " << name << "\n";
h5_api_test_sysProcess_SetTimeout(server, this->TimeOut);
h5_api_test_sysProcess_Execute(server);
int foundWaiting = 0;
string output;
while (!foundWaiting) {
int pipe = this->WaitForAndPrintLine(name, server, output, 100.0, out,
err, H5_API_TEST_SERVER_START_MSG, &foundWaiting);
if (pipe == h5_api_test_sysProcess_Pipe_None
|| pipe == h5_api_test_sysProcess_Pipe_Timeout) {
break;
}
}
if (foundWaiting) {
cerr << "H5APITestDriver: " << name << " successfully started.\n";
return 1;
} else {
cerr << "H5APITestDriver: " << name << " never started.\n";
h5_api_test_sysProcess_Kill(server);
return 0;
}
}
//----------------------------------------------------------------------------
int
H5APITestDriver::StartClientHelper(h5_api_test_sysProcess *client,
const char *name, vector<char> &out, vector<char> &err)
{
if (!client)
return 1;
cerr << "H5APITestDriver: starting process " << name << "\n";
h5_api_test_sysProcess_SetTimeout(client, this->TimeOut);
h5_api_test_sysProcess_Execute(client);
int foundWaiting = 0;
string output;
while (!foundWaiting) {
int pipe = this->WaitForAndPrintLine(name, client, output, 100.0, out,
err, H5_API_TEST_CLIENT_HELPER_START_MSG, &foundWaiting);
if (pipe == h5_api_test_sysProcess_Pipe_None
|| pipe == h5_api_test_sysProcess_Pipe_Timeout) {
break;
}
}
if (foundWaiting) {
cerr << "H5APITestDriver: " << name << " successfully started.\n";
return 1;
} else {
cerr << "H5APITestDriver: " << name << " never started.\n";
h5_api_test_sysProcess_Kill(client);
return 0;
}
}
//----------------------------------------------------------------------------
int
H5APITestDriver::StartClientInit(h5_api_test_sysProcess *client,
const char *name, vector<char> &out, vector<char> &err)
{
if (!client)
return 1;
cerr << "H5APITestDriver: starting process " << name << "\n";
h5_api_test_sysProcess_SetTimeout(client, this->TimeOut);
h5_api_test_sysProcess_Execute(client);
int foundToken = 0;
string output, token;
while (!foundToken) {
int pipe = this->WaitForAndPrintLine(name, client, output, 100.0, out,
err, NULL, NULL);
if (pipe == h5_api_test_sysProcess_Pipe_None
|| pipe == h5_api_test_sysProcess_Pipe_Timeout) {
break;
}
if (this->OutputStringHasToken(name, H5_API_TEST_CLIENT_INIT_TOKEN_REGEX, output, token)) {
foundToken = 1;
this->ClientTokenVar = std::string(H5_API_TEST_CLIENT_INIT_TOKEN_VAR)
+ std::string("=") + std::string(token);
break;
}
}
if (foundToken) {
cerr << "H5APITestDriver: " << name << " token: " << token << " was found.\n";
return 1;
} else {
cerr << "H5APITestDriver: " << name << " token was not found.\n";
return 0;
}
}
//----------------------------------------------------------------------------
int
H5APITestDriver::StartClient(h5_api_test_sysProcess *client, const char *name)
{
if (!client)
return 1;
cerr << "H5APITestDriver: starting process " << name << "\n";
h5_api_test_sysProcess_SetTimeout(client, this->TimeOut);
h5_api_test_sysProcess_Execute(client);
if (h5_api_test_sysProcess_GetState(client)
== h5_api_test_sysProcess_State_Executing) {
cerr << "H5APITestDriver: " << name << " successfully started.\n";
return 1;
} else {
this->ReportStatus(client, name);
h5_api_test_sysProcess_Kill(client);
return 0;
}
}
//----------------------------------------------------------------------------
void
H5APITestDriver::Stop(h5_api_test_sysProcess *p, const char *name)
{
if (p) {
cerr << "H5APITestDriver: killing process " << name << "\n";
h5_api_test_sysProcess_Kill(p);
h5_api_test_sysProcess_WaitForExit(p, 0);
}
}
//----------------------------------------------------------------------------
int
H5APITestDriver::OutputStringHasError(const char *pname, string &output)
{
const char* possibleMPIErrors[] = {"error", "Error", "Missing:",
"core dumped", "process in local group is dead", "Segmentation fault",
"erroneous", "ERROR:", "Error:",
"mpirun can *only* be used with MPI programs", "due to signal",
"failure", "abnormal termination", "failed", "FAILED", "Failed", 0};
const char* nonErrors[] = {
"Memcheck, a memory error detector", //valgrind
0};
if (this->AllowErrorInOutput)
return 0;
vector<string> lines;
vector<string>::iterator it;
h5_api_test_sys::SystemTools::Split(output.c_str(), lines);
int i, j;
for (it = lines.begin(); it != lines.end(); ++it) {
for (i = 0; possibleMPIErrors[i]; ++i) {
if (it->find(possibleMPIErrors[i]) != it->npos) {
int found = 1;
for (j = 0; nonErrors[j]; ++j) {
if (it->find(nonErrors[j]) != it->npos) {
found = 0;
cerr << "Non error \"" << it->c_str()
<< "\" suppressed " << std::endl;
}
}
if (found) {
cerr
<< "H5APITestDriver: ***** Test will fail, because the string: \""
<< possibleMPIErrors[i]
<< "\"\nH5APITestDriver: ***** was found in the following output from the "
<< pname << ":\n\"" << it->c_str() << "\"\n";
return 1;
}
}
}
}
return 0;
}
//----------------------------------------------------------------------------
int
H5APITestDriver::OutputStringHasToken(const char *pname, const char *regex,
string &output, string &token)
{
vector<string> lines;
vector<string>::iterator it;
h5_api_test_sys::SystemTools::Split(output.c_str(), lines);
h5_api_test_sys::RegularExpression re(regex);
for (it = lines.begin(); it != lines.end(); ++it) {
if (re.find(*it)) {
token = re.match(1);
return 1;
}
}
return 0;
}
//----------------------------------------------------------------------------
#define H5_API_CLEAN_PROCESSES do { \
h5_api_test_sysProcess_Delete(client); \
h5_api_test_sysProcess_Delete(client_helper); \
h5_api_test_sysProcess_Delete(client_init); \
h5_api_test_sysProcess_Delete(server); \
} while (0)
#define H5_API_EXECUTE_CMD(cmd) do { \
if (strlen(cmd) > 0) { \
std::vector<std::string> commands = \
h5_api_test_sys::SystemTools::SplitString(cmd, ';'); \
for (unsigned int cc = 0; cc < commands.size(); cc++) { \
std::string command = commands[cc]; \
if (command.size() > 0) { \
std::cout << command.c_str() << std::endl; \
system(command.c_str()); \
} \
} \
} \
} while (0)
//----------------------------------------------------------------------------
int
H5APITestDriver::Main(int argc, char* argv[])
{
#ifdef H5_API_TEST_INIT_COMMAND
// run user-specified commands before initialization.
// For example: "killall -9 rsh test;"
H5_API_EXECUTE_CMD(H5_API_TEST_INIT_COMMAND);
#endif
if (!this->ProcessCommandLine(argc, argv))
return 1;
this->CollectConfiguredOptions();
// mpi code
// Allocate process managers.
h5_api_test_sysProcess *server = 0;
h5_api_test_sysProcess *client = 0;
h5_api_test_sysProcess *client_helper = 0;
h5_api_test_sysProcess *client_init = 0;
if (this->TestServer) {
server = h5_api_test_sysProcess_New();
if (!server) {
H5_API_CLEAN_PROCESSES;
cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to "
"run the server.\n";
return 1;
}
}
if (this->ClientHelper) {
client_helper = h5_api_test_sysProcess_New();
if (!client_helper) {
H5API_CLEAN_PROCESSES;
cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to "
"run the client helper.\n";
return 1;
}
}
if (this->ClientInit) {
client_init = h5_api_test_sysProcess_New();
if (!client_init) {
H5_API_CLEAN_PROCESSES;
cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to "
"run the client init.\n";
return 1;
}
}
client = h5_api_test_sysProcess_New();
if (!client) {
H5_API_CLEAN_PROCESSES;
cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to "
"run the client.\n";
return 1;
}
vector<char> ClientStdOut;
vector<char> ClientStdErr;
vector<char> ClientHelperStdOut;
vector<char> ClientHelperStdErr;
vector<char> ClientInitStdOut;
vector<char> ClientInitStdErr;
vector<char> ServerStdOut;
vector<char> ServerStdErr;
vector<const char *> serverCommand;
if (server) {
const char* serverExe = this->ServerExecutable.c_str();
this->CreateCommandLine(serverCommand, serverExe, 1, 0,
this->MPIServerNumProcessFlag.c_str(), this->ServerArgStart,
this->ServerArgCount, argv);
this->ReportCommand(&serverCommand[0], "server");
h5_api_test_sysProcess_SetCommand(server, &serverCommand[0]);
h5_api_test_sysProcess_SetWorkingDirectory(server,
this->GetDirectory(serverExe).c_str());
}
vector<const char *> clientHelperCommand;
if (client_helper) {
// Construct the client helper process command line.
const char *clientHelperExe = this->ClientHelperExecutable.c_str();
this->CreateCommandLine(clientHelperCommand, clientHelperExe, 0, 1,
"1", this->ClientHelperArgStart,
this->ClientHelperArgCount, argv);
this->ReportCommand(&clientHelperCommand[0], "client_helper");
h5_api_test_sysProcess_SetCommand(client_helper, &clientHelperCommand[0]);
h5_api_test_sysProcess_SetWorkingDirectory(client_helper,
this->GetDirectory(clientHelperExe).c_str());
}
vector<const char *> clientInitCommand;
if (client_init) {
// Construct the client helper process command line.
const char *clientInitExe = this->ClientInitExecutable.c_str();
this->CreateCommandLine(clientInitCommand, clientInitExe, 0, 1,
"1", this->ClientInitArgStart, this->ClientInitArgCount, argv);
this->ReportCommand(&clientInitCommand[0], "client_init");
h5_api_test_sysProcess_SetCommand(client_init, &clientInitCommand[0]);
h5_api_test_sysProcess_SetWorkingDirectory(client_init,
this->GetDirectory(clientInitExe).c_str());
}
// Start the server if there is one
if (!this->StartServer(server, "server", ServerStdOut, ServerStdErr)) {
cerr << "H5APITestDriver: Server never started.\n";
H5_API_CLEAN_PROCESSES;
return -1;
}
// Start the client helper here if there is one
if (!this->StartClientHelper(client_helper, "client_helper",
ClientHelperStdOut, ClientHelperStdErr)) {
cerr << "H5APITestDriver: Client Helper never started.\n";
this->Stop(server, "server");
#ifdef H5_API_TEST_SERVER_EXIT_COMMAND
H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND);
#endif
H5_API_CLEAN_PROCESSES;
return -1;
}
// Start the client init here if there is one
if (!this->StartClientInit(client_init, "client_init",
ClientInitStdOut, ClientInitStdErr)) {
cerr << "H5APITestDriver: Client Init never started.\n";
this->Stop(server, "server");
#ifdef H5_API_TEST_SERVER_EXIT_COMMAND
H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND);
#endif
this->Stop(client_helper, "client_helper");
#ifdef H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND
H5_API_EXECUTE_CMD(H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND);
#endif
H5_API_CLEAN_PROCESSES;
return -1;
}
// Construct the client process command line.
vector<const char *> clientCommand;
const char *clientExe = this->ClientExecutable.c_str();
this->CreateCommandLine(clientCommand, clientExe, 0, 0,
this->MPIClientNumProcessFlag.c_str(), this->ClientArgStart,
this->ClientArgCount, argv);
this->ReportCommand(&clientCommand[0], "client");
h5_api_test_sysProcess_SetCommand(client, &clientCommand[0]);
h5_api_test_sysProcess_SetWorkingDirectory(client,
this->GetDirectory(clientExe).c_str());
// Now run the client
if (!this->StartClient(client, "client")) {
this->Stop(server, "server");
this->Stop(client_helper, "client_helper");
this->Stop(client_init, "client_init");
H5_API_CLEAN_PROCESSES;
return -1;
}
// Report the output of the processes.
int clientPipe = 1;
string output;
int mpiError = 0;
while (clientPipe) {
clientPipe = this->WaitForAndPrintLine("client", client, output, 0.1,
ClientStdOut, ClientStdErr, NULL, NULL);
if (!mpiError && this->OutputStringHasError("client", output)) {
mpiError = 1;
}
// If client has died, we wait for output from the server processes
// for this->ServerExitTimeOut, then we'll kill the servers, if needed.
double timeout = (clientPipe) ? 0 : this->ServerExitTimeOut;
output = "";
this->WaitForAndPrintLine("server", server, output, timeout,
ServerStdOut, ServerStdErr, NULL, NULL);
if (!mpiError && this->OutputStringHasError("server", output)) {
mpiError = 1;
}
output = "";
}
// Wait for the client and server to exit.
h5_api_test_sysProcess_WaitForExit(client, 0);
// Once client is finished, the servers
// must finish quickly. If not, it usually is a sign that
// the client crashed/exited before it attempted to connect to
// the server.
if (server) {
#ifdef H5_API_TEST_SERVER_EXIT_COMMAND
H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND);
#endif
h5_api_test_sysProcess_WaitForExit(server, &this->ServerExitTimeOut);
}
if (client_helper) {
#ifdef H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND
H5_API_EXECUTE_CMD(H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND);
#endif
h5_api_test_sysProcess_WaitForExit(client_helper, 0);
}
// Get the results.
int clientResult = this->ReportStatus(client, "client");
int serverResult = 0;
if (server) {
serverResult = this->ReportStatus(server, "server");
h5_api_test_sysProcess_Kill(server);
}
// Free process managers.
H5_API_CLEAN_PROCESSES;
// Report the server return code if it is nonzero. Otherwise report
// the client return code.
if (serverResult && !this->IgnoreServerResult)
return serverResult;
if (mpiError) {
cerr
<< "H5VLTestDriver: Error string found in output, H5APITestDriver returning "
<< mpiError << "\n";
return mpiError;
}
// if server is fine return the client result
return clientResult;
}
//----------------------------------------------------------------------------
void
H5APITestDriver::ReportCommand(const char * const *command, const char *name)
{
cerr << "H5APITestDriver: " << name << " command is:\n";
for (const char * const *c = command; *c; ++c)
cerr << " \"" << *c << "\"";
cerr << "\n";
}
//----------------------------------------------------------------------------
int
H5APITestDriver::ReportStatus(h5_api_test_sysProcess *process, const char *name)
{
int result = 1;
switch (h5_api_test_sysProcess_GetState(process)) {
case h5_api_test_sysProcess_State_Starting: {
cerr << "H5APITestDriver: Never started " << name << " process.\n";
}
break;
case h5_api_test_sysProcess_State_Error: {
cerr << "H5APITestDriver: Error executing " << name << " process: "
<< h5_api_test_sysProcess_GetErrorString(process) << "\n";
}
break;
case h5_api_test_sysProcess_State_Exception: {
cerr << "H5APITestDriver: " << name
<< " process exited with an exception: ";
switch (h5_api_test_sysProcess_GetExitException(process)) {
case h5_api_test_sysProcess_Exception_None: {
cerr << "None";
}
break;
case h5_api_test_sysProcess_Exception_Fault: {
cerr << "Segmentation fault";
}
break;
case h5_api_test_sysProcess_Exception_Illegal: {
cerr << "Illegal instruction";
}
break;
case h5_api_test_sysProcess_Exception_Interrupt: {
cerr << "Interrupted by user";
}
break;
case h5_api_test_sysProcess_Exception_Numerical: {
cerr << "Numerical exception";
}
break;
case h5_api_test_sysProcess_Exception_Other: {
cerr << "Unknown";
}
break;
}
cerr << "\n";
}
break;
case h5_api_test_sysProcess_State_Executing: {
cerr << "H5APITestDriver: Never terminated " << name
<< " process.\n";
}
break;
case h5_api_test_sysProcess_State_Exited: {
result = h5_api_test_sysProcess_GetExitValue(process);
cerr << "H5APITestDriver: " << name << " process exited with code "
<< result << "\n";
}
break;
case h5_api_test_sysProcess_State_Expired: {
cerr << "H5APITestDriver: killed " << name
<< " process due to timeout.\n";
}
break;
case h5_api_test_sysProcess_State_Killed: {
cerr << "H5APITestDriver: killed " << name << " process.\n";
}
break;
}
return result;
}
//----------------------------------------------------------------------------
int
H5APITestDriver::WaitForLine(h5_api_test_sysProcess *process, string &line,
double timeout, vector<char> &out, vector<char> &err)
{
line = "";
vector<char>::iterator outiter = out.begin();
vector<char>::iterator erriter = err.begin();
while (1) {
// Check for a newline in stdout.
for (; outiter != out.end(); ++outiter) {
if ((*outiter == '\r') && ((outiter + 1) == out.end())) {
break;
} else if (*outiter == '\n' || *outiter == '\0') {
int length = outiter - out.begin();
if (length > 1 && *(outiter - 1) == '\r')
--length;
if (length > 0)
line.append(&out[0], length);
out.erase(out.begin(), outiter + 1);
return h5_api_test_sysProcess_Pipe_STDOUT;
}
}
// Check for a newline in stderr.
for (; erriter != err.end(); ++erriter) {
if ((*erriter == '\r') && ((erriter + 1) == err.end())) {
break;
} else if (*erriter == '\n' || *erriter == '\0') {
int length = erriter - err.begin();
if (length > 1 && *(erriter - 1) == '\r')
--length;
if (length > 0)
line.append(&err[0], length);
err.erase(err.begin(), erriter + 1);
return h5_api_test_sysProcess_Pipe_STDERR;
}
}
// No newlines found. Wait for more data from the process.
int length;
char *data;
int pipe = h5_api_test_sysProcess_WaitForData(process, &data, &length,
&timeout);
if (pipe == h5_api_test_sysProcess_Pipe_Timeout) {
// Timeout has been exceeded.
return pipe;
} else if (pipe == h5_api_test_sysProcess_Pipe_STDOUT) {
// Append to the stdout buffer.
vector<char>::size_type size = out.size();
out.insert(out.end(), data, data + length);
outiter = out.begin() + size;
} else if (pipe == h5_api_test_sysProcess_Pipe_STDERR) {
// Append to the stderr buffer.
vector<char>::size_type size = err.size();
err.insert(err.end(), data, data + length);
erriter = err.begin() + size;
} else if (pipe == h5_api_test_sysProcess_Pipe_None) {
// Both stdout and stderr pipes have broken. Return leftover data.
if (!out.empty()) {
line.append(&out[0], outiter - out.begin());
out.erase(out.begin(), out.end());
return h5_api_test_sysProcess_Pipe_STDOUT;
} else if (!err.empty()) {
line.append(&err[0], erriter - err.begin());
err.erase(err.begin(), err.end());
return h5_api_test_sysProcess_Pipe_STDERR;
} else {
return h5_api_test_sysProcess_Pipe_None;
}
}
}
}
//----------------------------------------------------------------------------
void
H5APITestDriver::PrintLine(const char *pname, const char *line)
{
// if the name changed then the line is output from a different process
if (this->CurrentPrintLineName != pname) {
cerr << "-------------- " << pname << " output --------------\n";
// save the current pname
this->CurrentPrintLineName = pname;
}
cerr << line << "\n";
cerr.flush();
}
//----------------------------------------------------------------------------
int
H5APITestDriver::WaitForAndPrintLine(const char *pname,
h5_api_test_sysProcess *process, string &line, double timeout,
vector<char> &out, vector<char> &err, const char *waitMsg,
int *foundWaiting)
{
int pipe = this->WaitForLine(process, line, timeout, out, err);
if (pipe == h5_api_test_sysProcess_Pipe_STDOUT
|| pipe == h5_api_test_sysProcess_Pipe_STDERR) {
this->PrintLine(pname, line.c_str());
if (foundWaiting && (line.find(waitMsg) != line.npos))
*foundWaiting = 1;
}
return pipe;
}
//----------------------------------------------------------------------------
string
H5APITestDriver::GetDirectory(string location)
{
return h5_api_test_sys::SystemTools::GetParentDirectory(location.c_str());
}