Browse Source

Update test to test closeStdin() with multiple Child instances,

and to run under valgrind.

Note:  Valgrind reports 72,704 bytes reachable in testChild and childProgram.
This might not indicate any problem.


git-svn-id: https://svn.microneil.com/svn/CodeDweller-Tests/trunk@59 b3372362-9eaa-4a85-aa2b-6faa1ab7c995
master
adeniz 8 years ago
parent
commit
26f56e3de2
2 changed files with 178 additions and 23 deletions
  1. 22
    1
      TestChild/childProgram.cpp
  2. 156
    22
      TestChild/testChild.cpp

+ 22
- 1
TestChild/childProgram.cpp View File

#include <iostream> #include <iostream>
#ifdef DEBUG_MESSAGES
#include <fstream> // debug #include <fstream> // debug
#endif
#include <string> #include <string>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
#ifdef DEBUG_MESSAGES
std::ofstream log("childProgram.log"); std::ofstream log("childProgram.log");
#endif
int returnStatus = 25; // Successful return. int returnStatus = 25; // Successful return.
// Write a single line and exit. // Write a single line and exit.
if (std::string(argv[1]) == "write") { if (std::string(argv[1]) == "write") {
#ifdef DEBUG_MESSAGES
log << "Command is \"write\". Returning \"This is a test\"" log << "Command is \"write\". Returning \"This is a test\""
<< " to stdout and stderr." << std::endl; << " to stdout and stderr." << std::endl;
#endif
std::cout << "This "; std::cout << "This ";
std::cout.flush(); std::cout.flush();
// Exit without writing anything. // Exit without writing anything.
if (std::string(argv[1]) == "quit") { if (std::string(argv[1]) == "quit") {
#ifdef DEBUG_MESSAGES
log << "Command is \"quit\". Exiting" << std::endl; log << "Command is \"quit\". Exiting" << std::endl;
#endif
goto exit; goto exit;
} }
// Wait for standard input to close, and exit. // Wait for standard input to close, and exit.
if (std::string(argv[1]) == "checkStdinEOF") { if (std::string(argv[1]) == "checkStdinEOF") {
#ifdef DEBUG_MESSAGES
log << "Command is \"checkStdinEOF\". Checking that stdin is closed." log << "Command is \"checkStdinEOF\". Checking that stdin is closed."
<< std::endl; << std::endl;
#endif
std::string temp; std::string temp;
std::cin >> temp; std::cin >> temp;
if (std::cin.eof()) { if (std::cin.eof()) {
#ifdef DEBUG_MESSAGES
log << "stdin was closed." << std::endl; log << "stdin was closed." << std::endl;
#endif
returnStatus = 15; // Successful return. returnStatus = 15; // Successful return.
} else { } else {
#ifdef DEBUG_MESSAGES
log << "stdin was not closed." << std::endl; log << "stdin was not closed." << std::endl;
#endif
returnStatus = 10; // Unsuccessful return. returnStatus = 10; // Unsuccessful return.
} }
} }
char ch; char ch;
#ifdef DEBUG_MESSAGES
log << "Received \""; log << "Received \"";
#endif
while (std::cin >> ch) { while (std::cin >> ch) {
// Exit? // Exit?
if ('q' == ch) { if ('q' == ch) {
#ifdef DEBUG_MESSAGES
log << (char) ch << "\"" << std::endl; log << (char) ch << "\"" << std::endl;
#endif
break; break;
} }
std::cout << (char) std::toupper(ch); std::cout << (char) std::toupper(ch);
std::cout.flush(); std::cout.flush();
#ifdef DEBUG_MESSAGES
log << (char) ch; log << (char) ch;
log.flush(); log.flush();
#endif
} }
exit: exit:
#ifdef DEBUG_MESSAGES
log.close(); log.close();
#endif
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
return returnStatus; return returnStatus;

+ 156
- 22
TestChild/testChild.cpp View File

} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testChildNonblockingReadWrite2: " std::cout << " Failure in testChildNonblockingReadWrite2: "
child.flush(); child.flush();
// Sleep to let the child exit. // Sleep to let the child exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << "isDone() failure; returned false." << std::endl; std::cout << "isDone() failure; returned false." << std::endl;
} }
// Sleep to let the child exit. // Sleep to let the child exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << "isDone() failure; returned false." << std::endl; std::cout << "isDone() failure; returned false." << std::endl;
} }
// Sleep to let the child exit. // Sleep to let the child exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.close(); child.close();
} }
// Wait for the child to exit. // Wait for the child to exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
int32_t result = child.result(); int32_t result = child.result();
try { try {
CodeDweller::Child child(childName); CodeDweller::Child child(childName);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.close(); child.close();
} catch (std::exception &e) { } catch (std::exception &e) {
EXCEPTION_TERM("close() with 100 ms waiting"); EXCEPTION_TERM("close() with 100 ms waiting");
RETURN_FALSE(" write() failure"); RETURN_FALSE(" write() failure");
} }
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.close(); child.close();
child.closeStdIn(); child.closeStdIn();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
int32_t result = child.result(); int32_t result = child.result();
RETURN_FALSE(" write() failure"); RETURN_FALSE(" write() failure");
} }
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.closeStdIn(); child.closeStdIn();
} }
bool testChildrenStdInClose() {
std::string errorDescription;
int const nChildren = 5;
// Test with no child process.
try {
CodeDweller::Child child;
child.closeStdIn();
NO_EXCEPTION_TERM("closeStdIn() with no child process");
return false;
} catch (std::exception &e) {
}
// Test with no waiting.
try {
CodeDweller::Child child[nChildren];
for (int i = 0; i < nChildren; i++) {
child[i].open(childName);
}
for (int i = 0; i < nChildren; i++) {
child[i].closeStdIn();
}
for (int i = 0; i < nChildren; i++) {
child[i].close();
}
} catch (std::exception &e) {
EXCEPTION_TERM("closeStdIn() with no waiting");
return false;
}
// Run child that waits for stdin to close.
std::vector<std::string> cmd;
cmd.push_back(childName);
cmd.push_back("checkStdinEOF");
try {
CodeDweller::Child child[nChildren];
for (int i = 0; i < nChildren; i++ ) {
child[i].open(cmd);
}
for (int i = 0; i < nChildren; i++) {
child[i].closeStdIn();
}
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
for (int i = 0; i < nChildren; i++) {
int32_t result = child[i].result();
if (15 != result) {
std::cout << "closeStdIn() failure for child " << i << "; returned "
<< result << " instead of 15." << std::endl;
return false;
}
}
for (int i = 0; i < nChildren; i++) {
child[i].close();
}
for (int i = 0; i < nChildren; i++) {
if (child[i].errorOccurred(errorDescription)) {
std::ostringstream temp;
temp << " Failure in: testChildStdInClose for child " << i
<< ": " << errorDescription;
RETURN_FALSE(temp.str());
}
}
} catch (std::exception &e) {
EXCEPTION_TERM("closeStdIn() or close()");
return false;
}
// Test after the child exits.
cmd.clear();
cmd.push_back(childName);
cmd.push_back("quit");
try {
CodeDweller::Child child[nChildren];
for (int i = 0; i < nChildren; i++) {
child[i].open(cmd);
}
for (int i = 0; i < nChildren; i++) {
if (!child[i].write("q")) {
RETURN_FALSE(" write() failure");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
for (int i = 0; i < nChildren; i++) {
child[i].closeStdIn();
}
} catch (std::exception &e) {
EXCEPTION_TERM("closeStdIn() after child exits");
return false;
}
return true;
}
bool testChildOpen() { bool testChildOpen() {
// Test with no waiting. // Test with no waiting.
// Test with waiting. // Test with waiting.
try { try {
CodeDweller::Child child(childName); CodeDweller::Child child(childName);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.close(); child.close();
child.open(childName); child.open(childName);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
child.close(); child.close();
} catch (std::exception &e) { } catch (std::exception &e) {
EXCEPTION_TERM("close()/open() with 100 ms waiting"); EXCEPTION_TERM("close()/open() with 100 ms waiting");
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
if (0 != nCharToRead) { if (0 != nCharToRead) {
} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testReadWrite: Child program did not exit." std::cout << " Failure in testReadWrite: Child program did not exit."
} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testIsFinishedWriting: " std::cout << " Failure in testIsFinishedWriting: "
RETURN_FALSE(temp.str()); RETURN_FALSE(temp.str());
} }
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
} }
// Sleep to let the child exit. // Sleep to let the child exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
for (int i = 0; i < 100; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (child.isDone())
break;
}
if (!child.isDone()) { if (!child.isDone()) {
std::cout << "first isDone() failure in testReader." << std::endl; std::cout << "first isDone() failure in testReader." << std::endl;
RETURN_FALSE(" first write() failure"); RETURN_FALSE(" first write() failure");
} }
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
// Read one character. // Read one character.
std::string readBuf; std::string readBuf;
} }
// Wait for reader thread to fill input buffer. // Wait for reader thread to fill input buffer.
std::this_thread::sleep_for(std::chrono::milliseconds(25));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
if (child.read(readBuf) != expectedLeftOver) { if (child.read(readBuf) != expectedLeftOver) {
RETURN_FALSE(" read() failure"); RETURN_FALSE(" read() failure");
} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testChildNonblockingReadWrite1: " std::cout << " Failure in testChildNonblockingReadWrite1: "
RETURN_FALSE(" write() failure"); RETURN_FALSE(" write() failure");
} }
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
// Read one character. // Read one character.
std::vector<char> readBuf; std::vector<char> readBuf;
} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testChildVectorReadWrite: " std::cout << " Failure in testChildVectorReadWrite: "
RETURN_FALSE(" write() failure"); RETURN_FALSE(" write() failure");
} }
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
// Check // Check
std::vector<char> readVec; std::vector<char> readVec;
} }
// Verify exit. // Verify exit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
if (!child.isDone()) { if (!child.isDone()) {
std::cout << " Failure in testChildReadDelimited: " std::cout << " Failure in testChildReadDelimited: "
RUN_TEST(testChildResult); RUN_TEST(testChildResult);
RUN_TEST(testChildClose); RUN_TEST(testChildClose);
RUN_TEST(testChildStdInClose); RUN_TEST(testChildStdInClose);
RUN_TEST(testChildrenStdInClose);
RUN_TEST(testChildOpen); RUN_TEST(testChildOpen);
RUN_TEST(testChildIsFinishedWriting); RUN_TEST(testChildIsFinishedWriting);
RUN_TEST(testChildRead); RUN_TEST(testChildRead);

Loading…
Cancel
Save