Skip to content

Commit

Permalink
Re-Enable unittests
Browse files Browse the repository at this point in the history
Re-enabling the unit test infrastructure, adding new tests
for URI and linking existing tests into it. Some other tests
are not yet linked (aren't cppunit or aren't in a shared lib)
and will be done in the furure.

There is a good documentation on how to extend, and about each
part of the infrastructure. The remote tests are also a good
example on how to create more API/TDD unit tests in the future.
  • Loading branch information
rengolin committed Jul 11, 2012
1 parent d2a9a8e commit c3b0149
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 16 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ if ( NOT MAKE_DOCS_ONLY )
HPCC_ADD_SUBDIRECTORY (services "PLATFORM")
HPCC_ADD_SUBDIRECTORY (system)
HPCC_ADD_SUBDIRECTORY (thorlcr "PLATFORM")
HPCC_ADD_SUBDIRECTORY (testing)
endif()
HPCC_ADD_SUBDIRECTORY (docs "PLATFORM")
if (APPLE)
Expand Down
2 changes: 1 addition & 1 deletion common/remote/uri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ URI::URI(const char* path)
}

// Helper, to validate URI before creating object
bool isURI(const char *path)
bool URI::isURI(const char *path)
{
UriParserStateA state;
UriUriA uri;
Expand Down
19 changes: 15 additions & 4 deletions system/jlib/jutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,21 @@ HINSTANCE LoadSharedObject(const char *name, bool isGlobal, bool raiseOnError)
HINSTANCE h = dlopen((char *)name, isGlobal ? RTLD_NOW|RTLD_GLOBAL : RTLD_NOW);
if(h == NULL)
{
StringBuffer dlErrorMsg(dlerror());
DBGLOG("Error loading %s: %s", name, dlErrorMsg.str());
if (raiseOnError)
throw MakeStringException(0, "Error loading %s: %s", name, dlErrorMsg.str());
// Try again, with .so extension if necessary
if (strncmp(".so", name+(strlen(name)-3), 3) != 0)
{
// Assume if there's no .so, there's also no lib at the beginning
StringBuffer nameBuf;
nameBuf.append("lib").append(name).append(".so");
h = dlopen((char *)nameBuf.str(), isGlobal ? RTLD_NOW|RTLD_GLOBAL : RTLD_NOW);
}
if (h == NULL)
{
StringBuffer dlErrorMsg(dlerror());
DBGLOG("Error loading %s: %s", name, dlErrorMsg.str());
if (raiseOnError)
throw MakeStringException(0, "Error loading %s: %s", name, dlErrorMsg.str());
}
}

#endif
Expand Down
19 changes: 19 additions & 0 deletions testing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
################################################################################
# Copyright (C) 2012 HPCC Systems.
#
# This program is free software: you can redistribute it and/or All rights
# reserved. This program is NOT PRESENTLY free software: you can NOT
# redistribute
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
################################################################################
HPCC_ADD_SUBDIRECTORY (unittests)
49 changes: 49 additions & 0 deletions testing/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
################################################################################
# Copyright (C) 2012 HPCC Systems.
#
# All rights reserved. This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
################################################################################


# Component: unittests
#####################################################
# Description:
# ------------
# Cmake Input File for unittests
#####################################################

project( unitests )

set ( SRCS
unittests.cpp
remotetests.cpp
)

include_directories (
.
./../../system/include
./../../system/jlib
./../../common/remote
)

ADD_DEFINITIONS( -D_CONSOLE )

HPCC_ADD_EXECUTABLE ( unittests ${SRCS} )

install ( TARGETS unittests DESTINATION ${OSSDIR}/bin )
target_link_libraries ( unittests
jlib
remote
cppunit
)
111 changes: 111 additions & 0 deletions testing/unittests/remotetests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*##############################################################################
Copyright (C) 2012 HPCC Systems.
All rights reserved. This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
############################################################################## */

#ifdef _USE_CPPUNIT
#include "jlib.hpp"
#include "jlog.hpp"
#include "uri.hpp"

#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
// CPPUNIT_ASSERT is too slow, even when not matching failure
#define ASSERT(a) { if (!(a)) CPPUNIT_ASSERT(a); }

// =============================================================== jURI - URI parser
class URITests : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( URITests );
CPPUNIT_TEST(testURIError);
CPPUNIT_TEST(testURIUnknwon);
CPPUNIT_TEST(testURILocal);
CPPUNIT_TEST(testURIDali);
CPPUNIT_TEST_SUITE_END();
const IContextLogger &logctx;

void test_uri(const char * str, bool shouldBeURI, URISchemeType scheme=URIScheme_error, const char * server=NULL, const char * path=NULL)
{
bool isURI = URI::isURI(str);
ASSERT(isURI == shouldBeURI);
if (!isURI)
return;

// Now, validate URI
try
{
URI res(str);
ASSERT(res.getScheme() == scheme);
// No need to validate the rest
if (scheme == URIScheme_error)
return;
StringBuffer response;
res.appendServerStr(response);
ASSERT(strcmp(response.str(), server) == 0);
response.clear();
res.appendPathStr(response);
ASSERT(strcmp(response.str(), path) == 0);
}
catch (IException *e)
{
StringBuffer buf;
logctx.CTXLOG("Exception: %s", e->errorMessage(buf).str());
e->Release();
ASSERT(false); // Check exception log
}
}

public:
URITests() : logctx(queryDummyContextLogger()) {}

void testURIError() {
test_uri("You, shall not, pass!", false);
test_uri("http://almost there...", false);
}

void testURIUnknwon() {
test_uri("ftp://www.hpccsystems.com/", true);
test_uri("gopher://www.hpccsystems.com/", true);
test_uri("https://www.hpccsystems.com:443/", true);
test_uri("http://user:[email protected]:8080/my/path?is=full#of-stuff", true);
}

void testURILocal() {
test_uri("file:///opt/HPCCSystems/examples/IMDB/ActorsInMovies.ecl", true, URIScheme_file, "", "/opt/HPCCSystems/examples/IMDB/ActorsInMovies.ecl");
}

void testURIDali() {
// Dali file types
test_uri("hpcc://mydali/path/to/file", true, URIScheme_hpcc, "mydali", "path/to/file");
test_uri("hpcc://mydali/path/to/superfile?super", true, URIScheme_hpcc, "mydali", "path/to/superfile?super");
test_uri("hpcc://mydali/path/to/superfile?super#subname", true, URIScheme_hpcc, "mydali", "path/to/superfile?super#subname");
test_uri("hpcc://mydali/path/to/streamfile?stream", true, URIScheme_hpcc, "mydali", "path/to/streamfile?stream");
test_uri("hpcc://mydali/path/to/streamfile?stream#047", true, URIScheme_hpcc, "mydali", "path/to/streamfile?stream#47");

// Variations in Dali location
test_uri("hpcc://mydali:7070/path/to/file", true, URIScheme_hpcc, "mydali:7070", "path/to/file");
test_uri("hpcc://user@mydali:7070/path/to/file", true, URIScheme_hpcc, "user@mydali:7070", "path/to/file");
test_uri("hpcc://user@mydali/path/to/file", true, URIScheme_hpcc, "user@mydali", "path/to/file");
test_uri("hpcc://user:passwd@mydali:7070/path/to/file", true, URIScheme_hpcc, "user:passwd@mydali:7070", "path/to/file");
test_uri("hpcc://user:passwd@mydali/path/to/file", true, URIScheme_hpcc, "user:passwd@mydali", "path/to/file");
}
};

CPPUNIT_TEST_SUITE_REGISTRATION( URITests );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( URITests, "URITests" );

#endif // _USE_CPPUNIT
25 changes: 24 additions & 1 deletion testing/unittests/sourcedoc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,29 @@
<title>testing/unittests</title>

<para>
The testing/unittests directory contains the sources for the testing/unittests library.
The testing/unittests directory contains the sources for the unittests.
</para>
<para>
For internal unit tests, code the CPPUNIT test inside the CPP file that
declares/uses it and include the library in which they end up in here,
in unittest.cpp's loadDLLs().
</para>
<para>
For API tests, functionality checks and Test-Driven-Developement, create
a new cpp file in this directory with the set of tests and include it
in the CMakeLists.txt.
</para>
<para>
The difference between internal and API tests is that the former tests
have access to the internal classes, and can change states that other
classes don't, while the latter is seeing the classes as the rest of
HPCC does. So, the API tests also server as documentation on how to
use the API and to expose API problems.
</para>
<para>
Other binaries that include unit tests, and that ultimatelly should be
included in this framework, are: datest, daregress, daunittest, eclagent,
roxie. Test ncbd (which is part of both eclagent and roxie) is already in
thorhelper.
</para>
</section>
57 changes: 47 additions & 10 deletions testing/unittests/unittests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,58 @@

#define ASSERT(a) { if (!(a)) CPPUNIT_ASSERT(a); }

void loadDll(const char *name)
{
SharedObject *so = new SharedObject;
so->load(name, true);
}
/*
* This is the main unittest driver for HPCC. From here,
* all unit tests, be them internal or external (API).
*
* All internal unit tests, written on the same source
* files as the implementation they're testing, can be
* dynamically linked via the helper class below.
*
* All external unit tests (API tests, test-driven
* development, interface documentation and general
* usability tests) should be implemented as source
* files within the same directory as this file, and
* statically linked together.
*
* CPPUnit will automaticall recognise and run them all.
*/

void loadDlls()
{
loadDll("jhtree");
}
/*
* Helper class to unload libraries at the end
* and make sure the SharedObject gets deleted
* correctly.
*
* This is important to run valgrind tests and not
* having to care about which memory leaks are "good"
* and which are not.
*/
class LoadedObject : public IInterface, CInterface {
SharedObject *so;
public:
IMPLEMENT_IINTERFACE;

LoadedObject(const char * name)
{
so = new SharedObject;
so->load(name, true);
}
~LoadedObject()
{
so->unload();
delete so;
}
};

int main(int argc, char* argv[])
{
loadDlls();
InitModuleObjects();
// These are the internal unit tests covered by other modules and libraries
Array objects;
objects.append(*(new LoadedObject ("jhtree")));
objects.append(*(new LoadedObject ("roxiemem")));
objects.append(*(new LoadedObject ("thorhelper")));

queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_time);
CppUnit::TextUi::TestRunner runner;
if (argc==1)
Expand Down

0 comments on commit c3b0149

Please sign in to comment.