Skip to content

Commit

Permalink
ENH: Improve error reporting in ctkDICOMApplicationTest1
Browse files Browse the repository at this point in the history
Check for process exit code and introduce `run_process` and `wait_for_finished`
convenience functions.
  • Loading branch information
jcfr committed Jan 13, 2024
1 parent c695808 commit ced3c3c
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 97 deletions.
10 changes: 9 additions & 1 deletion Applications/Testing/Cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@ if(CTK_APP_ctkDICOMQuery AND CTK_APP_ctkDICOMRetrieve)
# Add Tests
#
ctk_add_executable_utf8(ctkDICOMApplicationTest1 ctkDICOMApplicationTest1.cpp)
target_link_libraries(ctkDICOMApplicationTest1 Qt${CTK_QT_VERSION}::Core)
target_link_libraries(ctkDICOMApplicationTest1
CTKCore
Qt${CTK_QT_VERSION}::Core
)

include_directories(
${CTKCore_SOURCE_DIR}
${CTKCore_BINARY_DIR}
)

set(testname ctkDICOMApplicationTest1)

Expand Down
269 changes: 173 additions & 96 deletions Applications/Testing/Cpp/ctkDICOMApplicationTest1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
// Qt includes
#include <QTextStream>
#include <QCoreApplication>
#include <QFileInfo>
#include <QProcess>

// CTK includes
#include "ctkCoreTestingMacros.h"

// STD includes
#include <iostream>
#include <cstdlib>
Expand Down Expand Up @@ -59,6 +63,128 @@
//
*/

namespace
{

//-----------------------------------------------------------------------------
enum WaitType
{
WaitForStarted, //!< Blocks until the process has started
WaitForFinished, //!< Blocks until the process has finished
};

//-----------------------------------------------------------------------------
int wait_for_finished(QTextStream& out, const QString& type, QProcess* process, bool kill=false)
{
try
{
QString programName = QFileInfo(process->program()).baseName();

if (kill)
{
process->kill();
}

process->waitForFinished();

out << "------------------------------------------------------------------------------\n";
out << "------------------------------------------------------------------------------\n";
out << "------------------------------------------------------------------------------\n";
out << type << " " << programName << " Finished.\n";

out << "Process Killed: " << (kill ? "yes" : "no") << "\n";

out << "Process ExitCode: ";
if (process->exitCode() == QProcess::NormalExit)
{
out << "NormalExit (" << static_cast<int>(QProcess::NormalExit) << ")\n";
}
else
{
out << "CrashExit (" << static_cast<int>(QProcess::CrashExit) << ")\n";
}

if (process->exitCode() == QProcess::CrashExit)
{
out << "Process State: ";
switch(static_cast<int>(process->error()))
{

#define _QProcessErrorToString(ERROR) \
case QProcess::ERROR: \
out << #ERROR << " (" << static_cast<int>(QProcess::ERROR) << ")\n"; \
break;

_QProcessErrorToString(FailedToStart);
_QProcessErrorToString(Crashed);
_QProcessErrorToString(Timedout);
_QProcessErrorToString(WriteError);
_QProcessErrorToString(ReadError);
_QProcessErrorToString(UnknownError);

#undef _QProcessErrorToString
}
}
out << "Standard Output:\n";
out << process->readAllStandardOutput();
out << "Standard Error:\n";
out << process->readAllStandardError();

if (kill)
{
return EXIT_SUCCESS;
}
else
{
return process->exitStatus() == QProcess::NormalExit ? process->exitCode() : EXIT_FAILURE;
}
}
catch (const std::exception& e)
{
out << "ERROR: exception ocurred in wait_for_finished(): " << e.what();
return EXIT_FAILURE;
}
}

//-----------------------------------------------------------------------------
int run_process(
QTextStream& out, const QString& type, WaitType wait_type,
QProcess* process, const QString& exectuable, const QStringList& arguments)
{
try
{
QString programName = QFileInfo(exectuable).baseName();

out << "------------------------------------------------------------------------------\n";
out << "------------------------------------------------------------------------------\n";
out << "------------------------------------------------------------------------------\n";
out << "starting " << type << " " << exectuable << "\n";
out << "with args " << arguments.join(" ") << "\n";
process->start(exectuable, arguments);
switch(wait_type)
{
case WaitForStarted:
process->waitForStarted();
out << programName << " Started.\n";
return process->state() == QProcess::Running ? EXIT_SUCCESS : EXIT_FAILURE;

case WaitForFinished:
return wait_for_finished(out, type, process);

default:
return EXIT_FAILURE;
}
}
catch (const std::exception& e)
{
out << "ERROR: exception ocurred in run_process(): " << e.what();
return EXIT_FAILURE;
}
}

} // end of anonymous namespace

//-----------------------------------------------------------------------------
int main(int argc, char * argv []) {

QCoreApplication app(argc, argv);
Expand Down Expand Up @@ -86,23 +212,15 @@ int main(int argc, char * argv []) {
//

QProcess *dcmqrscp = new QProcess(0);
QStringList dcmqrscp_args;
dcmqrscp_args << "--config" << dcmqrscp_cfg;
dcmqrscp_args << "--debug" << "--verbose";
dcmqrscp_args << "11112";

try
{
out << "starting server " << dcmqrscp_exe << "\n";
out << "with args " << dcmqrscp_args.join(" ") << "\n";
dcmqrscp->start(dcmqrscp_exe, dcmqrscp_args);
dcmqrscp->waitForStarted();
out << "dcmqrscp Started.\n";
}
catch (const std::exception& e)
{
out << "ERROR: could not start server " << e.what();
return EXIT_FAILURE;
CHECK_EXIT_SUCCESS(
run_process(out, "server", WaitForStarted, dcmqrscp, dcmqrscp_exe,
{
"--config", dcmqrscp_cfg,
"--debug",
"--verbose",
"11112"
}));
}


Expand All @@ -111,58 +229,38 @@ int main(int argc, char * argv []) {
//

QProcess *storescu = new QProcess(0);
QStringList storescu_args;
storescu_args << "-aec" << "CTK_AE";
storescu_args << "-aet" << "CTK_AE";
storescu_args << "localhost" << "11112";
storescu_args << dicomData1;
storescu_args << dicomData2;

try
{
out << "running client " << storescu_exe << "\n";
out << "with args " << storescu_args.join(" ") << "\n";
storescu->start(storescu_exe, storescu_args);
storescu->waitForFinished();
out << "storescu Finished.\n";
out << "Standard Output:\n";
out << storescu->readAllStandardOutput();
out << "Standard Error:\n";
out << storescu->readAllStandardError();
}
catch (const std::exception& e)
{
out << "ERROR: could not start client " << e.what();
return EXIT_FAILURE;
CHECK_EXIT_SUCCESS(
run_process(out, "client", WaitForFinished, storescu, storescu_exe,
{
"-aec", "CTK_AE",
"-aet", "CTK_AE",
"localhost", "11112",
dicomData1,
dicomData2,
}));
}


//
// now query the server to see if the data arrived okay
// - our database file will be updated with metadata from the query
//

QProcess *ctkDICOMQuery = new QProcess(0);
QStringList ctkDICOMQuery_args;
ctkDICOMQuery_args << ctkDICOMQuery_db_file;
ctkDICOMQuery_args << "CTK_AE" << "CTK_AE";
ctkDICOMQuery_args << "localhost" << "11112";

try
{
out << "running client " << ctkDICOMQuery_exe << "\n";
out << "with args " << ctkDICOMQuery_args.join(" ") << "\n";
ctkDICOMQuery->start(ctkDICOMQuery_exe, ctkDICOMQuery_args);
ctkDICOMQuery->waitForFinished();
out << "ctkDICOMQuery Finished.\n";
out << "Standard Output:\n";
out << ctkDICOMQuery->readAllStandardOutput();
out << "Standard Error:\n";
out << ctkDICOMQuery->readAllStandardError();
}
catch (const std::exception& e)
{
out << "ERROR: could not start client " << e.what();
return EXIT_FAILURE;
// Usage:
// ctkDICOMQuery database callingAETitle calledAETitle host port

CHECK_EXIT_SUCCESS(
run_process(out, "client", WaitForFinished, ctkDICOMQuery, ctkDICOMQuery_exe,
{
ctkDICOMQuery_db_file,
"CTK_AE",
"CTK_AE",
"localhost",
"11112"
}));
}


Expand All @@ -174,50 +272,29 @@ int main(int argc, char * argv []) {
QString studyUID("1.2.840.113619.2.135.3596.6358736.5118.1115807980.182");

QProcess *ctkDICOMRetrieve = new QProcess(0);
QStringList ctkDICOMRetrieve_args;
ctkDICOMRetrieve_args << studyUID;
ctkDICOMRetrieve_args << ctkDICOMRetrieve_directory;
ctkDICOMRetrieve_args << "CTK_AE";
ctkDICOMRetrieve_args << "CTK_AE";
ctkDICOMRetrieve_args << "localhost" << "11112" << "CTK_CLIENT_AE";

try
{
out << "running client " << ctkDICOMRetrieve_exe << "\n";
out << "with args " << ctkDICOMRetrieve_args.join(" ") << "\n";
ctkDICOMRetrieve->start(ctkDICOMRetrieve_exe, ctkDICOMRetrieve_args);
ctkDICOMRetrieve->waitForFinished();
out << "ctkDICOMRetrieve Finished.\n";
out << "Standard Output:\n";
out << ctkDICOMRetrieve->readAllStandardOutput();
out << "Standard Error:\n";
out << ctkDICOMRetrieve->readAllStandardError();
}
catch (const std::exception& e)
{
out << "ERROR: could not start client " << e.what();
return EXIT_FAILURE;
// Usage:
// ctkDICOMRetrieve StudyUID OutputDirectory callingAETitle calledAETitle host calledPort moveDestinationAETitle

CHECK_EXIT_SUCCESS(
run_process(out, "client", WaitForFinished, ctkDICOMRetrieve, ctkDICOMRetrieve_exe,
{
studyUID,
ctkDICOMRetrieve_directory,
"CTK_AE",
"CTK_AE",
"localhost",
"11112",
"CTK_CLIENT_AE"
}));
}


//
// clients are finished, not kill server and print output
// clients are finished, now kill server and print output
//
try
{
dcmqrscp->kill();
dcmqrscp->waitForFinished();
out << "dcmqrscp Finished.\n";
out << "Standard Output:\n";
out << dcmqrscp->readAllStandardOutput();
out << "Standard Error:\n";
out << dcmqrscp->readAllStandardError();
}
catch (const std::exception& e)
{
out << "ERROR: could not start client " << e.what();
return EXIT_FAILURE;
}
CHECK_EXIT_SUCCESS(
wait_for_finished(out, "server", dcmqrscp, /*kill=*/true));

return EXIT_SUCCESS;
}
Expand Down

0 comments on commit ced3c3c

Please sign in to comment.