summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJesse Gilles <jgilles@multitech.com>2015-04-20 17:14:31 -0500
committerJesse Gilles <jgilles@multitech.com>2015-04-20 17:14:31 -0500
commitd84d880627bcc1e1898a8f96b861bc25863ec86c (patch)
treee7db4eef6a8e8254eaa6ba0c7e5d56098af19d16 /test
downloadlibmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.tar.gz
libmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.tar.bz2
libmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.zip
initial commit
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt9
-rw-r--r--test/TestRunnerClient.cpp566
-rw-r--r--test/TestRunnerClient.h147
3 files changed, 722 insertions, 0 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..64428e9
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,9 @@
+project (TestRunnerClient)
+
+include_directories (../include)
+link_directories (..)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -DCPPUNIT_MAIN=main")
+
+add_executable (TestRunnerClient TestRunnerClient.cpp )
+target_link_libraries (TestRunnerClient cppunit mts mts_io ssl rt pthread)
diff --git a/test/TestRunnerClient.cpp b/test/TestRunnerClient.cpp
new file mode 100644
index 0000000..fcb9c75
--- /dev/null
+++ b/test/TestRunnerClient.cpp
@@ -0,0 +1,566 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Gerhard Leonhartsberger.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+#include "TestRunnerClient.h"
+
+#ifdef CPPUNIT_MAIN
+
+#include "cppunit/XmlOutputter.h"
+#include "cppunit/TextOutputter.h"
+#include "cppunit/TestSuite.h"
+#include "cppunit/TestResult.h"
+#include "cppunit/TestFailure.h"
+#include "cppunit/SourceLine.h"
+#include "cppunit/Exception.h"
+#include "cppunit/extensions/TestFactoryRegistry.h"
+#include "cppunit/extensions/TestDecorator.h"
+#include "cppunit/ui/text/TestRunner.h"
+
+#include <iostream>
+#include <sstream>
+#include <typeinfo>
+#include <vector>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef _WIN32 // Bugzilla 40710
+#include <windows.h>
+#include <winbase.h>
+#include <winsock.h>
+#else
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#define MAX_HOSTNAME_SIZE 255
+
+/*
+ * CppUnitServer protocol constants
+ */
+static const std::string TRACE_START = "%TRACES ";
+static const std::string TRACE_END = "%TRACEE ";
+static const std::string TEST_RUN_START = "%TESTC ";
+static const std::string TEST_START = "%TESTS ";
+static const std::string TEST_END = "%TESTE ";
+static const std::string TEST_ERROR = "%ERROR ";
+static const std::string TEST_FAILED = "%FAILED ";
+static const std::string TEST_RUN_END = "%RUNTIME";
+static const std::string TEST_STOPPED = "%TSTSTP ";
+static const std::string TEST_TREE = "%TSTTREE";
+
+TestRunnerClient::TestRunnerClient()
+{
+ fTestResult = 0;
+ fClientSocket = -1;
+ fPort = 0;
+ fKeepAlive = 0;
+ fDebugMode = 0;
+
+ fHost = (char *) malloc(MAX_HOSTNAME_SIZE);
+ strcpy(fHost, "");
+}
+
+TestRunnerClient::~TestRunnerClient() {
+
+ if (fHost != NULL) {
+ free(fHost);
+ }
+}
+
+int TestRunnerClient::Run()
+{
+ if (fDebugMode)
+ {
+ std::cerr << "TestRunnerClient: Starting client." << std::endl;
+ }
+
+ if (Connect() == -1) {
+ return -1;
+ }
+
+ InstallListeners();
+
+ RunTests();
+
+ UninstallListeners();
+
+ if(fTestResult != NULL)
+ {
+ fTestResult->stop();
+ fTestResult= NULL;
+ }
+
+ ShutDown();
+
+ return 0;
+}
+
+void TestRunnerClient::Init(int n, char *args[])
+{
+ ParseCommandLine(n, args);
+ DefineHostName();
+}
+
+void TestRunnerClient::ParseCommandLine(int n, char *args[])
+{
+ // parse all arguments passed by args
+ for(int i = 0; i < n; i++)
+ {
+ std::string arg(args[i]);
+
+ // port option
+ std::string portOption("-port=");
+ int pos = arg.find(portOption);
+ if(pos> -1)
+ {
+ std::string v = arg.substr(pos + portOption.length(), arg.length());
+ fPort = atoi(v.c_str());
+ }
+
+ // debug option
+ std::string debugOption("-debug");
+ pos = arg.find(debugOption);
+ if(pos> - 1)
+ {
+ fDebugMode = 1;
+ }
+ }
+}
+
+void TestRunnerClient::DefineHostName()
+{
+ // set fHost to hostname or localhost
+ int ret = gethostname(fHost, MAX_HOSTNAME_SIZE);
+ if (ret == -1)
+ {
+ strcpy(fHost, "localhost");
+ }
+}
+
+int TestRunnerClient::Connect()
+{
+
+#ifdef _WIN32 // Bugzilla 40710
+ if (fDebugMode)
+ {
+ std::cerr << "TestRunnerClient: Starting Windows Sockets WSAStartup()." << std:endl;
+ }
+
+ // start up Windows Sockets
+ WSADATA WSAData;
+ int result = WSAStartup (MAKEWORD(1, 1), &WSAData);
+ if (result != NO_ERROR)
+ {
+ std::cerr << "TestRunnerClient: WSAStartup() failed! Error code: " << result << std::endl;
+ return -1;
+ }
+#endif
+
+ if (fDebugMode)
+ {
+ std::cerr << "TestRunnerClient: Trying to connect to " << fHost << ":" << fPort << std::endl;
+ }
+
+ fClientSocket = socket(AF_INET, SOCK_STREAM, 0);
+ if (fClientSocket == -1)
+ {
+ std::cerr << "TestRunnerClient: Socket creation failed! error code: " << fClientSocket << std::endl;
+ return -1;
+ }
+
+ struct hostent *host = gethostbyname(fHost);
+ if (host == NULL)
+ {
+ std::cerr << "TestRunnerClient: Cannot find host address for " << fHost << "." << std::endl;
+ fClientSocket = -1;
+ return -1;
+ }
+
+ struct sockaddr_in name;
+ memset((void *)&name, 0, sizeof(struct sockaddr_in));
+ name.sin_family = AF_INET;
+ name.sin_port = htons(fPort);
+
+ memcpy(&name.sin_addr, host->h_addr, host->h_length);
+
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Waiting for the JVM to listen ... (trying 3 times)" << std::endl;
+ }
+
+ int ret = -1;
+ int j = 0;
+ while ((j < 3) && (ret == -1))
+ {
+ ret = ::connect(fClientSocket, (struct sockaddr *) &name, sizeof(struct sockaddr_in));
+ if (ret == -1)
+ {
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Connection request, waiting 1 second. "
+ << ((j-3)*-1) << " times left." << std::endl;
+ }
+ PrivateSleep(1000);
+ j++;
+ }
+ }
+ if (ret == -1)
+ {
+ std::cerr << "TestRunnerClient: No connection established. Error code: " << errno << std::endl;
+ fClientSocket = -1;
+ return -1;
+ }
+
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Connection established." << std::endl;
+ }
+ return 0;
+}
+
+void TestRunnerClient::InstallListeners()
+{
+ fTestResult = new CppUnit::TestResult();
+ fTestResult->addListener(this);
+ fTestResult->addListener(&resultCollector);
+}
+
+void TestRunnerClient::UninstallListeners()
+{
+ fTestResult->removeListener(this);
+}
+
+void TestRunnerClient::RunTests()
+{
+
+ CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ CppUnit::Test *suite = registry.makeTest();
+ int count = suite->countTestCases();
+ NotifyTestRunStarted(count);
+
+ if (count == 0)
+ {
+ NotifyTestRunEnded(0);
+ }
+
+ long startTime = CurrentTimeMillis();
+ if (fDebugMode)
+ {
+ std::cerr <<"TestRunnerClient: Start sending test case tree ..." << std::endl;
+ }
+
+ SendTestTree(suite);
+
+ int elapsedTime = CurrentTimeMillis() - startTime;
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Done sending test case tree. Elapsed time is "
+ << elapsedTime << "ms." << std::endl;
+ }
+
+ long testStartTime = CurrentTimeMillis();
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Test start time is " << testStartTime
+ << "ms." << std::endl;
+ }
+
+ suite->run(fTestResult);
+
+ if (fTestResult == NULL || fTestResult->shouldStop())
+ {
+ NotifyTestRunStopped(CurrentTimeMillis() - testStartTime);
+ }
+ else
+ {
+ NotifyTestRunEnded(CurrentTimeMillis() - testStartTime);
+ }
+}
+
+void TestRunnerClient::ShutDown()
+{
+ if (fClientSocket != -1)
+ {
+ if (fDebugMode) {
+ std::cerr << "TestRunnerClient: Closing connection to CppUnit sever at "
+ << fHost << ":" << fPort << std::endl;
+ }
+
+#ifdef _WIN32 // Bugzilla 40710
+ // TODO: std:err output for error return codes
+ closesocket(fClientSocket);
+ WSACleanup();
+#else
+ int result = close(fClientSocket);
+ if (result != 0)
+ {
+ std::cerr << "TestRunnerClient: Close connection error: " << errno << std::endl;
+ }
+#endif
+
+ fClientSocket = -1;
+ }
+}
+
+void TestRunnerClient::Stop()
+{
+ if (fTestResult != NULL)
+ {
+ fTestResult->stop();
+ }
+}
+
+void TestRunnerClient::SendTestTree(CppUnit::Test *test)
+{
+ if (typeid(*test) == typeid(CppUnit::TestDecorator))
+ {
+ class TmpClass : public CppUnit::TestDecorator {
+
+ public:
+ TmpClass(Test *t):CppUnit::TestDecorator(t)
+ {
+ // nothing to do
+ }
+
+ ~TmpClass() // Bugzilla 39894
+ {
+ // nothing to do
+ }
+
+ CppUnit::Test *getTest()
+ {
+ return m_test;
+ }
+ };
+
+ TmpClass *t = (TmpClass *)test;
+ SendTestTree(t->getTest());
+ }
+ else if (typeid(*test) == typeid(CppUnit::TestSuite))
+ {
+ CppUnit::TestSuite *suite = (CppUnit::TestSuite *)test;
+ const std::vector<CppUnit::Test *> &x = suite->getTests();
+
+ std::ostringstream os;
+ os << suite->getName() << ",true," << x.size();
+ NotifyTestTreeEntry(os.str());
+
+ for(unsigned int i=0; i < x.size(); i++)
+ {
+ SendTestTree(x[i]);
+ }
+ }
+ else
+ {
+ std::ostringstream os;
+ os << test->getName() << ",false," << test->countTestCases();
+ NotifyTestTreeEntry(os.str());
+ }
+}
+
+void TestRunnerClient::SendMessage(std::string msg)
+{
+ if (fClientSocket == -1)
+ {
+ return;
+ }
+
+#ifdef _WIN32 // Bugzilla 40710
+ send (fClientSocket, msg.c_str(), msg.length(), 0);
+ send (fClientSocket, "\n", 1, 0);
+#else
+ write(fClientSocket, msg.c_str(), msg.length());
+ write(fClientSocket, "\n", 1);
+#endif
+
+ if (fDebugMode)
+ {
+ std::cerr << "TestRunnerClient: Sent message \"" << msg << "\""
+ << std::endl;
+ }
+}
+
+void TestRunnerClient::NotifyTestRunStarted(int testCount)
+{
+ std::ostringstream os;
+ os << TEST_RUN_START << testCount;
+ SendMessage(os.str());
+}
+
+void TestRunnerClient::NotifyTestRunEnded(long elapsedTime)
+{
+ std::ostringstream os;
+ os << TEST_RUN_END << elapsedTime;
+ SendMessage(os.str());
+}
+
+void TestRunnerClient::NotifyTestRunStopped(long elapsedTime)
+{
+ std::ostringstream os;
+ os << TEST_STOPPED << elapsedTime;
+ SendMessage(os.str());
+}
+
+void TestRunnerClient::NotifyTestTreeEntry(std::string treeEntry)
+{
+ SendMessage(TEST_TREE + treeEntry);
+}
+
+void TestRunnerClient::NotifyTestStarted(std::string testName)
+{
+ SendMessage(TEST_START + testName);
+}
+
+void TestRunnerClient::NotifyTestEnded(std::string testName)
+{
+ SendMessage(TEST_END + testName);
+}
+
+void TestRunnerClient::NotifyTestFailed(std::string status, std::string testName, std::string trace)
+{
+ SendMessage(status + testName);
+ SendMessage(TRACE_START);
+ SendMessage(trace);
+ SendMessage(TRACE_END);
+}
+
+// From TestListener
+void TestRunnerClient::startTest(CppUnit::Test *test)
+{
+ NotifyTestStarted(test->getName());
+}
+
+// From TestListener
+void TestRunnerClient::addFailure(const CppUnit::TestFailure &failure)
+{
+ if(failure.isError())
+ {
+ NotifyTestFailed(TEST_ERROR,failure.failedTestName(),GetTrace(failure));
+ }
+ else
+ {
+ NotifyTestFailed(TEST_FAILED,failure.failedTestName(),GetTrace(failure));
+ }
+}
+
+// From TestListener
+void TestRunnerClient::endTest(CppUnit::Test *test)
+{
+ NotifyTestEnded(test->getName());
+}
+
+std::string TestRunnerClient::GetTrace(const CppUnit::TestFailure &failure)
+{
+ std::ostringstream os;
+
+ CppUnit::Exception *e=failure.thrownException();
+ if(e->sourceLine().lineNumber()!=-1)
+ {
+ os << "File " << e->sourceLine().fileName() << ":" << e->sourceLine().lineNumber() << "\n";
+ }
+ else
+ {
+ os << "File Unknown:1\n";
+ }
+ /* TODO: expected, actual value implementation
+ if(typeid(*e)==typeid(CppUnit::NotEqualException))
+ {
+ CppUnit::NotEqualException *ne=(CppUnit::NotEqualException *)e;
+
+ os << "Expected Value: " << ne->expectedValue() << "\n";
+ os << "Actual Value: " << ne->expectedValue() << "\n";
+ os << "Additional Message: " << ne->additionalMessage() << "\n";
+ }
+ else
+ {
+ End */
+ os << "Message: " << std::string(e->what()) << "\n";
+ /* } */
+
+ return(os.str());
+}
+
+long TestRunnerClient::CurrentTimeMillis()
+{
+#ifdef _WIN32 // Bugzilla 40710
+ unsigned long long p;
+ __asm__ __volatile__ ("rdtsc" : "=A" (p));
+ return (unsigned long)p;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return((long)(tv.tv_sec*1000) + (tv.tv_usec/1000));
+#endif
+}
+
+void TestRunnerClient::PrivateSleep(int millisecs)
+{
+ struct timeval delta;
+ delta.tv_sec = (millisecs * 1000L) / 1000000L;
+ delta.tv_usec = (millisecs * 1000L) % 1000000L;
+ select (0, NULL, NULL, NULL, &delta);
+}
+
+CppUnit::TestResultCollector& TestRunnerClient::getResultCollector() {
+ return resultCollector;
+}
+
+/*!
+ * This is the main routine. The TestRunnerClient is initialized and run. The
+ * CppUnit tests are created, executed, and sent to the CppUnitServer.
+ * If no connection to the CppUnitServer was established the CppUnit tests are
+ * displayed on the console.
+ *
+ * @return <code>0</code> if the results of the CppUnit tests were sent to the
+ * CppUnitServer successfully.
+ * <code>-1</code> if a connection could not be established to the
+ * CppUnitServer.
+ */
+int CPPUNIT_MAIN(int n, char *arg[])
+{
+ std::ofstream xmlFileOut("cppunit_results.xml");
+
+ TestRunnerClient client;
+ client.Init(n, arg);
+ int ret = client.Run();
+ if (ret == -1)
+ {
+ //The Test Runner Client has failed
+ //Create the event manager and test controller
+
+ CppUnit::TestResult controller;
+
+ // Add a listener that collects test result
+ CppUnit::TestResultCollector result;
+ controller.addListener ( &result );
+
+ CppUnit::XmlOutputter xmlOutputter ( &result, xmlFileOut );
+ CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ CppUnit::Test *suite = registry.makeTest();
+
+ CppUnit::TextUi::TestRunner *runner = new CppUnit::TextUi::TestRunner();
+ runner->addTest(suite);
+ runner->run(controller);
+
+ // Output to XML
+ xmlOutputter.write();
+ } else {
+
+ CppUnit::TextOutputter textOutputter (&client.getResultCollector(), std::cout);
+ textOutputter.write();
+
+ // Output to XML
+ CppUnit::XmlOutputter xmlOutputter ( &client.getResultCollector(), xmlFileOut );
+ xmlOutputter.write();
+ }
+
+
+ xmlFileOut.close();
+}
+
+#endif /*CPPUNIT_MAIN*/
diff --git a/test/TestRunnerClient.h b/test/TestRunnerClient.h
new file mode 100644
index 0000000..4dc4460
--- /dev/null
+++ b/test/TestRunnerClient.h
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Gerhard Leonhartsberger.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+#ifndef TESTRUNNERSERVER_H_
+#define TESTRUNNERSERVER_H_
+
+#ifdef CPPUNIT_MAIN
+
+#include "cppunit/TestResultCollector.h"
+#include "cppunit/TestListener.h"
+
+#include <vector>
+#include <string>
+#include <string.h>
+#include <stdlib.h>
+
+
+/*!
+ * Class <code>TestRunnerClient</code> handles the network connection to the
+ * <code>CppUnitServer</code> and executes all registered CppUnit tests.
+ * <p>
+ * The meta data of the CppUnit tests and the test results are sent to the
+ * <code>CppUnitServer</code> for displaying.
+ * </p>
+ * <p>
+ * For debugging purposes class <code>TestRunnerClient</code> displays debug
+ * messages on <code>std.cerr</code>. The debug modus is activated by specifying
+ * <code>debug</code> command line option. The command line is parsed by method
+ * <code>Init()</code>.
+ * </p>
+ * <p>
+ * Note: This class is not intended to be subclassed by clients. This class is
+ * based on the original <code>RemoteTestRunner</code> class provided by
+ * <code>org.eclipse.cdt.cppunit</code>.
+ * </p>
+ *
+ * @author Gerhard Leonhartsberger
+ */
+class TestRunnerClient: public CppUnit::TestListener
+{
+private:
+ CppUnit::TestResult *fTestResult;
+ CppUnit::TestResultCollector resultCollector;
+ int fClientSocket;
+ char *fHost;
+ int fPort;
+ int fDebugMode;
+ int fKeepAlive;
+
+public:
+ TestRunnerClient();
+ virtual ~TestRunnerClient();
+
+ CppUnit::TestResultCollector& getResultCollector();
+
+ /*!
+ * Initializes the <code>TestRunnerClient</code>.
+ * <p>
+ * The given <code>args</code> are parsed. The syntax for the arguments is
+ * defined in EBNF as follows: <code>{-option=value}</code>
+ * </p>
+ *
+ * @param n The number of arguments.
+ * @param args The argument values. Valid options are:
+ * <li><code>-debug</code> When present the TestRunnerClient
+ * is run in debug modus and displays debug messages.</li>
+ * <li><code>-port=number</code> Defines the port where
+ * CppUnitServer is listening for client connections.</li>
+ */
+ void Init(int n,char *args[]);
+
+ /*!
+ * Runs the TestRunnerClient. A trial to connect to the CppUnitServer is done.
+ * The test results are sent to the CppUnitServer.
+ *
+ * @return The return value is <code>0</code> when the CppUnitServer was connected successfully
+ * otherwise the return value is <code>-1</code>.
+ */
+ int Run();
+
+ /*!
+ * Stops processing <code>CppUnit</code> from executing tests.
+ */
+ void Stop();
+
+ /*!
+ * Method defined in <code>CppUnit::TestListener</code>.
+ */
+ void startTest(CppUnit::Test *test);
+
+ /*!
+ * Method defined in <code>CppUnit::TestListener</code>.
+ */
+ void addFailure(const CppUnit::TestFailure &failure);
+
+ /*!
+ * Method defined in <code>CppUnit::TestListener</code>.
+ */
+ void endTest(CppUnit::Test *test);
+
+private:
+ int Connect();
+ void RunTests();
+ void ShutDown();
+
+ // utility methods
+ void ParseCommandLine(int n, char *args[]);
+ void DefineHostName();
+ void InstallListeners();
+ void UninstallListeners();
+
+ /*!
+ * Sends the given test to the CppUnitView.
+ * <p>
+ * In case of test is of type CppUnit::Test the following protocol is sent:
+ * <code>TSTTREE name, false, testCaseCount</code>
+ * </p>
+ * <p>
+ * In case of test is of type CppUnit::TestSuite the following protocol is sent:
+ * TSTTREE name, true, testCount
+ * </p>
+ * @param test the CppUnit test
+ */
+ void SendTestTree(CppUnit::Test *test);
+ void SendMessage(std::string msg);
+
+ // Notification methods
+ void NotifyTestRunStarted(int testCount);
+ void NotifyTestRunEnded(long elapsedTime);
+ void NotifyTestRunStopped(long elapsedTime);
+ void NotifyTestTreeEntry(std::string treeEntry);
+ void NotifyTestStarted(std::string testName);
+ void NotifyTestEnded(std::string testName);
+ void NotifyTestFailed(std::string status, std::string testName, std::string trace);
+
+ std::string GetTrace(const CppUnit::TestFailure &failure);
+ long CurrentTimeMillis();
+ void PrivateSleep(int millisecs);
+};
+
+#endif /*CPPUNIT_MAIN*/
+#endif /*TESTRUNNERSERVER_H_*/