|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// 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);
|