Commit c09bb445 authored by Victor Kotlyar's avatar Victor Kotlyar
Browse files

Removed dublicated code for SupProcess

parent 65ac160e
......@@ -23,6 +23,7 @@
#include "SubProcess.hpp"
#include "common/exception/Errnum.hpp"
#include <memory>
#include <string.h>
#include <iostream>
#include <sys/signal.h>
......@@ -98,14 +99,20 @@ SubProcess::SubProcess(const std::string & executable, const std::list<std::stri
ScopedPosixSpawnAttr attr;
cta::exception::Errnum::throwOnReturnedErrno(posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK),
"In Subprocess::Subprocess(): failed to posix_spawnattr_setflags()");
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());
{
std::unique_ptr<char *[]> cargv (new char*[argv.size()+1]);
size_t index = 0;
std::list<std::unique_ptr<char, void (*)(char *)>> cargvStrings;
for (auto a=argv.cbegin(); a!=argv.cend(); a++) {
cargv[index] = ::strdup(a->c_str());
std::unique_ptr<char, void (*)(char *)> upStr (cargv[index], [](char *s){::free(s);});
cargvStrings.emplace_back(std::move(upStr));
index++;
}
cargv[argv.size()] = NULL;
int spawnRc=::posix_spawnp(&m_child, executable.c_str(), fileActions, attr, cargv.get(), ::environ);
cta::exception::Errnum::throwOnReturnedErrno(spawnRc, "In Subprocess::Subprocess failed to posix_spawn()");
}
cargv[argv.size()] = NULL;
int spawnRc=::posix_spawnp(&m_child, executable.c_str(), fileActions, attr, cargv, ::environ);
cta::exception::Errnum::throwOnReturnedErrno(spawnRc, "In Subprocess::Subprocess failed to posix_spawn()");
// We are the parent process. Close the write sides of pipes.
::close(stdoutPipe[writeSide]);
::close(stderrPipe[writeSide]);
......
......@@ -19,8 +19,7 @@ add_library(cta-tapedSystemTests SHARED
cta-tapedSystemtests.cpp)
target_link_libraries(cta-tapedSystemTests
systemTestHelper
unitTestHelper
ctacommon)
install(TARGETS cta-tapedSystemTests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
\ No newline at end of file
install(TARGETS cta-tapedSystemTests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
......@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tests/Subprocess.hpp"
#include "common/threading/SubProcess.hpp"
#include "tests/TempFile.hpp"
#include <gtest/gtest.h>
......@@ -25,12 +25,12 @@ namespace systemTests {
TEST(cta_taped, InvocationTests) {
{
// Do we get help with -h or --help?
Subprocess spHelpShort("cta-taped", std::list<std::string>({"cta-taped", "-h"}));
cta::threading::SubProcess spHelpShort("cta-taped", std::list<std::string>({"cta-taped", "-h"}));
spHelpShort.wait();
ASSERT_NE(std::string::npos, spHelpShort.stdout().find("Usage"));
ASSERT_TRUE(spHelpShort.stderr().empty());
ASSERT_EQ(EXIT_SUCCESS, spHelpShort.exitValue());
Subprocess spHelpLong("cta-taped", std::list<std::string>({"cta-taped", "--help"}));
cta::threading::SubProcess spHelpLong("cta-taped", std::list<std::string>({"cta-taped", "--help"}));
spHelpLong.wait();
ASSERT_NE(std::string::npos, spHelpLong.stdout().find("Usage: cta-taped [options]"));
ASSERT_TRUE(spHelpLong.stderr().empty());
......@@ -39,7 +39,7 @@ TEST(cta_taped, InvocationTests) {
{
// Do we get proper complaint when the configuration file is not there?
Subprocess spNoConfigFile("cta-taped", std::list<std::string>({"cta-taped", "-f", "-s", "-c", "/no/such/file"}));
cta::threading::SubProcess spNoConfigFile("cta-taped", std::list<std::string>({"cta-taped", "-f", "-s", "-c", "/no/such/file"}));
spNoConfigFile.wait();
ASSERT_NE(std::string::npos, spNoConfigFile.stdout().find("Failed to open configuration file"));
ASSERT_TRUE(spNoConfigFile.stderr().empty());
......@@ -58,11 +58,11 @@ TEST(cta_taped, InvocationTests) {
"taped BufferCount 1\n"
"taped TpConfigPath ");
ctaConf.stringAppend(tpConfig.path());
Subprocess spNoDrive("cta-taped", std::list<std::string>({"cta-taped", "-f", "-s", "-c", ctaConf.path()}));
cta::threading::SubProcess spNoDrive("cta-taped", std::list<std::string>({"cta-taped", "-f", "-s", "-c", ctaConf.path()}));
spNoDrive.wait();
ASSERT_NE(std::string::npos, spNoDrive.stdout().find("MSG=\"Aborting\" Message=\"No drive found in configuration\""));
ASSERT_TRUE(spNoDrive.stderr().empty());
ASSERT_EQ(EXIT_FAILURE, spNoDrive.exitValue());
}
}
}
\ No newline at end of file
}
......@@ -75,14 +75,10 @@ target_link_libraries(cta-unitTests-multiProcess
add_library(unitTestHelper
TempFile.cpp)
add_library(systemTestHelper
Subprocess.cpp)
add_library(systemTestHelperTests SHARED
SubprocessSystemTests.cpp)
target_link_libraries(systemTestHelperTests
systemTestHelper
ctacommon)
add_executable(cta-systemTests
......@@ -90,7 +86,6 @@ add_executable(cta-systemTests
${GMOCK_SRC})
target_link_libraries(cta-systemTests
systemTestHelper
systemTestHelperTests
cta-tapedSystemTests
gtest
......
/*
* 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>
#include <unistd.h>
#include <spawn.h>
#include <memory>
namespace {
class ScopedPosixSpawnFileActions{
public:
ScopedPosixSpawnFileActions() {
::posix_spawn_file_actions_init(&m_action);
}
~ScopedPosixSpawnFileActions() {
::posix_spawn_file_actions_destroy(&m_action);
}
operator ::posix_spawn_file_actions_t * () { return &m_action; }
private:
::posix_spawn_file_actions_t m_action;
};
}
namespace {
class ScopedPosixSpawnAttr{
public:
ScopedPosixSpawnAttr() {
::posix_spawnattr_init(&m_attr);
}
~ScopedPosixSpawnAttr() {
::posix_spawnattr_destroy(&m_attr);
}
operator ::posix_spawnattr_t * () { return &m_attr; }
private:
::posix_spawnattr_t m_attr;
};
}
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");
// Prepare the actions to be taken on file descriptors
ScopedPosixSpawnFileActions fileActions;
// We will be the child process. Close the read sides of the pipes.
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_addclose(fileActions, stdoutPipe[readSide]),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_addclose() (1)");
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_addclose(fileActions, stderrPipe[readSide]),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_addclose() (2)");
// Close stdin and rewire the stdout and stderr to the pipes.
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_adddup2(fileActions, stdoutPipe[writeSide], STDOUT_FILENO),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_adddup2() (1)");
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_adddup2(fileActions, stderrPipe[writeSide], STDERR_FILENO),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_adddup2() (2)");
// Close the now duplicated pipe file descriptors
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_addclose(fileActions, stdoutPipe[writeSide]),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_addclose() (3)");
cta::exception::Errnum::throwOnReturnedErrno(posix_spawn_file_actions_addclose(fileActions, stderrPipe[writeSide]),
"In Subprocess::Subprocess(): failed to posix_spawn_file_actions_addclose() (4)");
// And finally spawn the subprocess
// Prepare the spawn attributes (we need vfork)
ScopedPosixSpawnAttr attr;
cta::exception::Errnum::throwOnReturnedErrno(posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK),
"In Subprocess::Subprocess(): failed to posix_spawnattr_setflags()");
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;
int spawnRc=::posix_spawnp(&m_child, executable.c_str(), fileActions, attr, cargv, ::environ);
cta::exception::Errnum::throwOnReturnedErrno(spawnRc, "In Subprocess::Subprocess failed to posix_spawn()");
// 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];
}
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();
}
}
} // namespace systemTests
\ 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
......@@ -16,26 +16,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Subprocess.hpp"
#include "common/threading/SubProcess.hpp"
#include <gtest/gtest.h>
namespace systemTests {
TEST(SuprocessHelper, basicTests) {
Subprocess sp("echo", std::list<std::string>({"echo", "Hello,", "world."}));
TEST(SubProcessHelper, basicTests) {
cta::threading::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"}));
cta::threading::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());
Subprocess sp3("/no/such/file", std::list<std::string>({"/no/such/file"}));
cta::threading::SubProcess sp3("/no/such/file", std::list<std::string>({"/no/such/file"}));
sp3.wait();
ASSERT_EQ("", sp3.stdout());
ASSERT_EQ(127, sp3.exitValue());
ASSERT_EQ("", sp3.stderr());
}
}
\ No newline at end of file
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment