Skip to content
Snippets Groups Projects
Commit fcfa6d05 authored by Eric Cano's avatar Eric Cano
Browse files

Created a helper class to start sub processes for the system test.

Created an embryo system test.
parent 0f7e5f7d
No related branches found
No related tags found
No related merge requests found
......@@ -46,3 +46,25 @@ target_link_libraries(unitTests
${GMOCK_LIB}
gtest
pthread)
add_library(systemTestHelper
Subprocess.cpp)
add_library(systemTestHelperTests SHARED
SubprocessSystemTests.cpp)
target_link_libraries(systemTestHelperTests
systemTestHelper
ctacommon)
add_executable(systemTests
system_tests.cpp
${GMOCK_SRC})
target_link_libraries(systemTests
systemTestHelper
systemTestHelperTests
gtest
pthread)
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Subprocess.hpp"
#include "common/exception/Errnum.hpp"
#include <string.h>
#include <iostream>
#include <sys/signal.h>
#include <sys/wait.h>
#include <fcntl.h>
namespace systemTests {
Subprocess::Subprocess(const std::string & executable, const std::list<std::string>& argv) {
// Sanity checks
if (argv.size() < 1)
throw cta::exception::Exception(
"In Subprocess::Subprocess: not enough elements in argv");
// Prepare the pipes for the child's stdout and stderr (stdin will be closed)
const size_t readSide=0;
const size_t writeSide=1;
int stdoutPipe[2];
int stderrPipe[2];
cta::exception::Errnum::throwOnNonZero(::pipe2(stdoutPipe, O_NONBLOCK),
"In Subprocess::Subprocess failed to create the stdout pipe");
cta::exception::Errnum::throwOnNonZero(::pipe2(stderrPipe, O_NONBLOCK),
"In Subprocess::Subprocess failed to create the stderr pipe");
cta::exception::Errnum::throwOnMinusOne(m_child = fork(),
"In Subprocess::Subprocess failed to fork");
if (m_child) {
// We are the parent process. Close the write sides of pipes.
::close(stdoutPipe[writeSide]);
::close(stderrPipe[writeSide]);
m_stdoutFd = stdoutPipe[readSide];
m_stderrFd = stderrPipe[readSide];
} else {
try {
// We are in the child process. Close the read sides of the pipes.
::close(stdoutPipe[readSide]);
::close(stderrPipe[readSide]);
// Close stdin and rewire the stdout and stderr to the pipes.
::close(STDIN_FILENO);
cta::exception::Errnum::throwOnMinusOne(
::dup2(stdoutPipe[writeSide], STDOUT_FILENO),
"In Subprocess::Subprocess failed to dup2 stdout pipe");
cta::exception::Errnum::throwOnMinusOne(
::dup2(stderrPipe[writeSide], STDERR_FILENO),
"In Subprocess::Subprocess failed to dup2 stderr pipe");
// Close the now duplicated pipe file descriptors
::close(stdoutPipe[writeSide]);
::close(stderrPipe[writeSide]);
// Finally execv the command
char ** cargv = new char*[argv.size()+1];
int index = 0;
for (auto a=argv.cbegin(); a!=argv.cend(); a++) {
cargv[index++] = ::strdup(a->c_str());
}
cargv[argv.size()] = NULL;
cta::exception::Errnum::throwOnMinusOne(
execvp(executable.c_str(), cargv));
// We should never get here.
throw cta::exception::Exception(
"In Subprocess::Subprocess execv failed without returning -1!");
} catch (cta::exception::Exception & ex) {
std::cerr << ex.getMessageValue();
exit(EXIT_FAILURE);
}
}
}
void Subprocess::kill(int signal) {
::kill(m_child, signal);
}
int Subprocess::exitValue() {
if(!m_child)
throw cta::exception::Exception("In Subprocess::exitValue: child process not waited for");
return WEXITSTATUS(m_childStatus);
}
void Subprocess::wait() {
::waitpid(m_child, &m_childStatus, 0);
char buff[1000];
int rc;
while (0<(rc=::read(m_stdoutFd, buff, sizeof(buff)))) {
m_stdout.append(buff, rc);
}
::close(m_stdoutFd);
while (0<(rc=::read(m_stderrFd, buff, sizeof(buff)))) {
m_stderr.append(buff, rc);
}
::close(m_stderrFd);
m_childComplete = true;
}
std::string Subprocess::stdout() {
if(!m_child)
throw cta::exception::Exception("In Subprocess::stdout: child process not waited for");
return m_stdout;
}
std::string Subprocess::stderr() {
if(!m_child)
throw cta::exception::Exception("In Subprocess::stderr: child process not waited for");
return m_stderr;
}
Subprocess::~Subprocess() {
if(!m_childComplete) {
this->kill(SIGKILL);
this->wait();
}
}
}
\ No newline at end of file
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <list>
#include <string>
namespace systemTests {
class Subprocess {
public:
Subprocess(const std::string & program, const std::list<std::string> &argv);
~Subprocess();
void wait(void);
std::string stdout();
std::string stderr();
void kill(int signal);
int exitValue();
private:
int m_stdoutFd;
int m_stderrFd;
pid_t m_child;
bool m_childComplete;
int m_childStatus;
std::string m_stdout;
std::string m_stderr;
};
}
\ No newline at end of file
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Subprocess.hpp"
#include <gtest/gtest.h>
namespace systemTests {
TEST(SuprocessHelper, basicTests) {
Subprocess sp("echo", std::list<std::string>({"echo", "Hello,", "world."}));
sp.wait();
ASSERT_EQ("Hello, world.\n", sp.stdout());
ASSERT_EQ("", sp.stderr());
ASSERT_EQ(0, sp.exitValue());
Subprocess sp2("cat", std::list<std::string>({"cat", "/no/such/file"}));
sp2.wait();
ASSERT_EQ("", sp2.stdout());
ASSERT_NE(std::string::npos, sp2.stderr().find("/no/such/file"));
ASSERT_EQ(1, sp2.exitValue());
}
}
\ No newline at end of file
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
#include <gmock/gmock.h>
// This is a simplified main for system tests. There is not point in using
// valgrind with it, and we will not use gmock with it either (pure gtest).
int main(int argc, char** argv) {
int newArgc = argc;
::testing::InitGoogleTest(&newArgc, argv);
return RUN_ALL_TESTS();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment