Commit f707f9c6 authored by Eric Cano's avatar Eric Cano
Browse files

Added missing virtual destructors for ChildProcess and Cleanup classes.

Moved multi process tests into a new binary, as memcheck fails them (a lot of test framework related structures are still allocated at exit time).
parent ef544d41
add_library(castorTapeServerThreading Threading.cpp ChildProcess.cpp)
\ No newline at end of file
add_library(castorTapeServerThreading Threading.cpp ChildProcess.cpp)
target_link_libraries(castorTapeServerThreading Exception)
\ No newline at end of file
......@@ -43,6 +43,7 @@ namespace threading {
class Cleanup {
public:
virtual void operator() () = 0;
virtual ~Cleanup() {}
};
/**
* Exceptions for wrong usage.
......@@ -67,6 +68,8 @@ namespace threading {
ChildProcess(): m_started(false), m_finished(false), m_exited(false),
m_wasKilled(false) {}
/* Clean up leftover child processes (hopefully not useful) */
virtual ~ChildProcess() { if (m_started && !m_finished) kill(); };
/** start function, taking as an argument a callback for parent's
* resources cleanup. A child process can only be fired once. */
void start(Cleanup & cleanup) throw (castor::tape::Exception);
......
/******************************************************************************
* ThreadingTests.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include <gtest/gtest.h>
#include "Threading.hpp"
#include "ChildProcess.hpp"
/* This is a collection of multi process unit tests, which can (and should)
be passed through helgrind, but not valgrind as the test framework creates
many memory leaks in the child process. */
namespace ThreadedUnitTests {
class emptyCleanup : public castor::tape::threading::ChildProcess::Cleanup {
public:
virtual void operator ()() { };
};
class myOtherProcess : public castor::tape::threading::ChildProcess {
private:
int run() {
/* Just sleep a bit so the parent process gets a chance to see us running */
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10*1000*1000;
nanosleep(&ts, NULL);
return 123;
}
};
TEST(castor_tape_threading, ChildProcess_return_value) {
myOtherProcess cp;
emptyCleanup cleanup;
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessNeverStarted);
EXPECT_NO_THROW(cp.start(cleanup));
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessStillRunning);
EXPECT_NO_THROW(cp.wait());
ASSERT_EQ(123, cp.exitCode());
}
class myInfiniteSpinner : public castor::tape::threading::ChildProcess {
private:
int run() {
/* Loop forever (politely) */
while (true) {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10*1000*1000;
nanosleep(&ts, NULL);
}
return 321;
}
};
TEST(castor_tape_threading, ChildProcess_killing) {
myInfiniteSpinner cp;
emptyCleanup cleanup;
EXPECT_THROW(cp.kill(), castor::tape::threading::ChildProcess::ProcessNeverStarted);
EXPECT_NO_THROW(cp.start(cleanup));
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessStillRunning);
ASSERT_EQ(true, cp.running());
EXPECT_NO_THROW(cp.kill());
/* The effect is not immediate, wait a bit. */
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10*1000*1000;
nanosleep(&ts, NULL);
ASSERT_EQ(false, cp.running());
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessWasKilled);
}
};
......@@ -24,10 +24,9 @@
#include <gtest/gtest.h>
#include "Threading.hpp"
#include "ChildProcess.hpp"
/* This is a collection of multi threaded unit tests, which can (and should
be passed through helgrind). */
/* This is a collection of multi threaded unit tests, which can (and should)
be passed through helgrind, as well as valgrind */
namespace ThreadedUnitTests {
......@@ -117,66 +116,5 @@ namespace ThreadedUnitTests {
ASSERT_NE(std::string::npos, w.find("Exception in child thread"));
}
}
class emptyCleanup : public castor::tape::threading::ChildProcess::Cleanup {
public:
virtual void operator ()() { };
};
class myOtherProcess : public castor::tape::threading::ChildProcess {
private:
int run() {
/* Just sleep a bit so the parent process gets a chance to see us running */
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 50000;
nanosleep(&ts, NULL);
return 123;
}
};
TEST(castor_tape_threading, ChildProcess_return_value) {
myOtherProcess cp;
emptyCleanup cleanup;
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessNeverStarted);
EXPECT_NO_THROW(cp.start(cleanup));
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessStillRunning);
EXPECT_NO_THROW(cp.wait());
ASSERT_EQ(123, cp.exitCode());
}
class myInfiniteSpinner : public castor::tape::threading::ChildProcess {
private:
int run() {
/* Loop forever (politely) */
while (true) {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10*1000*1000;
nanosleep(&ts, NULL);
}
return 321;
}
};
TEST(castor_tape_threading, ChildProcess_killing) {
myInfiniteSpinner cp;
emptyCleanup cleanup;
EXPECT_THROW(cp.kill(), castor::tape::threading::ChildProcess::ProcessNeverStarted);
EXPECT_NO_THROW(cp.start(cleanup));
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessStillRunning);
ASSERT_EQ(true, cp.running());
EXPECT_NO_THROW(cp.kill());
/* The effect is not immediate, wait a bit. */
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10*1000*1000;
nanosleep(&ts, NULL);
ASSERT_EQ(false, cp.running());
EXPECT_THROW(cp.exitCode(), castor::tape::threading::ChildProcess::ProcessWasKilled);
}
} // namespace ThreadedUnitTests
......@@ -4,4 +4,6 @@ valgrind --leak-check=full --show-reachable=yes --error-exitcode=1 test/castorUn
test/castorThreadedUnitTests
valgrind --leak-check=full --show-reachable=yes --error-exitcode=1 test/castorThreadedUnitTests
valgrind --tool=helgrind --error-exitcode=1 test/castorThreadedUnitTests
test/castorMultiprocessUnitTests
valgrind --tool=helgrind --error-exitcode=1 test/castorMultiprocessUnitTests
%endif
%if 0%{?castorUnitTest:1} > 0
%attr(0755,root,root) usr/bin/castorUnitTests
%attr(0755,root,root) usr/bin/castorThreadedUnitTests
%attr(0755,root,root) usr/bin/castorMultiprocessUnitTests
%endif
......@@ -51,5 +51,15 @@ target_link_libraries(castorThreadedUnitTests TapeDrive Exception SCSI System
Utils File castorTapeServerThreading
${GTEST_LIBRARY} gmock pthread castorcommon)
install(TARGETS castorUnitTests castorThreadedUnitTests
# Those tests are multi threaded. They could should also be run in
# helgrind/drd (but not memcheck)
add_executable(castorMultiprocessUnitTests
castorUnitTests.cpp
../castor/tape/tapeserver/threading/ThreadingMPTests.cpp
)
target_link_libraries(castorMultiprocessUnitTests TapeDrive Exception SCSI System
Utils File castorTapeServerThreading
${GTEST_LIBRARY} gmock pthread castorcommon)
install(TARGETS castorUnitTests castorThreadedUnitTests castorMultiprocessUnitTests
DESTINATION ${CASTOR_DEST_BIN_DIR})
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