Преглед на файлове

HPCC-13029 Clean up unit tests

Rework the unittest program to allow finer control over what tests are to be
run, load all dlls, allow inclusionand exclusion, etc.

Delay initialization on Dali unit tests until it is proven they are included.

Recategorise some jlib tests as "timing" or "stress" to exclude from the
standard unittest runs.

Fix some failing tests.

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman преди 9 години
родител
ревизия
b719c4d642

+ 0 - 142
common/thorhelper/roxiehelper.cpp

@@ -885,141 +885,6 @@ public:
     }
 };
 
-class CInsertionSortAlgorithm : public CSortAlgorithm
-{
-    SortedBlock *curBlock;
-    unsigned blockNo;
-    IArrayOf<SortedBlock> blocks;
-    unsigned activityId;
-    roxiemem::IRowManager *rowManager;
-    ICompare *compare;
-
-    void newBlock()
-    {
-        blocks.append(*curBlock);
-        curBlock = new SortedBlock(blockNo++, rowManager, activityId);
-    }
-
-    inline static int doCompare(SortedBlock &l, SortedBlock &r, ICompare *compare)
-    {
-        return l.compareTo(&r, compare);
-    }
-
-    void makeHeap()
-    {
-        /* Permute blocks to establish the heap property
-           For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
-           The children of p must both be greater than or equal to p
-           The parent of a child c is given by p = (c-1)/2
-        */
-        unsigned i;
-        unsigned n = blocks.length();
-        SortedBlock **s = blocks.getArray();
-        for (i=1; i<n; i++)
-        {
-            SortedBlock * r = s[i];
-            int c = i; /* child */
-            while (c > 0)
-            {
-                int p = (c-1)/2; /* parent */
-                if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
-                    break;
-                s[c] = s[p];
-                s[p] = r;
-                c = p;
-            }
-        }
-    }
-
-    void remakeHeap()
-    {
-        /* The row associated with block[0] will have changed
-           This code restores the heap property
-        */
-        unsigned p = 0; /* parent */
-        unsigned n = blocks.length();
-        SortedBlock **s = blocks.getArray();
-        while (1)
-        {
-            unsigned c = p*2 + 1; /* child */
-            if ( c >= n )
-                break;
-            /* Select smaller child */
-            if ( c+1 < n && doCompare( blocks.item(c+1), blocks.item(c), compare ) < 0 ) c += 1;
-            /* If child is greater or equal than parent then we are done */
-            if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
-                break;
-            /* Swap parent and child */
-            SortedBlock *r = s[c];
-            s[c] = s[p];
-            s[p] = r;
-            /* child becomes parent */
-            p = c;
-        }
-    }
-
-public:
-    CInsertionSortAlgorithm(ICompare *_compare, roxiemem::IRowManager *_rowManager, unsigned _activityId)
-        : compare(_compare)
-    {
-        rowManager = _rowManager;
-        activityId = _activityId;
-        curBlock = NULL;
-        blockNo = 0;
-    }
-
-    virtual void reset()
-    {
-        blocks.kill();
-        delete curBlock;
-        curBlock = NULL;
-        blockNo = 0;
-    }
-
-    virtual void prepare(IEngineRowStream *input)
-    {
-        blockNo = 0;
-        curBlock = new SortedBlock(blockNo++, rowManager, activityId);
-        loop
-        {
-            const void *next = input->nextRow();
-            if (!next)
-                break;
-            if (!curBlock->insert(next, compare))
-            {
-                newBlock();
-                curBlock->insert(next, compare);
-            }
-        }
-        if (blockNo > 1)
-        {
-            blocks.append(*curBlock);
-            curBlock = NULL;
-            makeHeap();
-        }
-    }
-
-    virtual const void * next()
-    {
-        const void *ret;
-        if (blockNo==1) // single block case..
-        {
-            ret = curBlock->next();
-        }
-        else if (blocks.length())
-        {
-            SortedBlock &top = blocks.item(0);
-            ret = top.next();
-            if (top.eof())
-                blocks.replace(blocks.popGet(), 0);
-            remakeHeap();
-        }
-        else
-            ret = NULL;
-        return ret;
-    }
-};
-
 class CHeapSortAlgorithm : public CSortAlgorithm
 {
     unsigned curIndex;
@@ -1461,11 +1326,6 @@ extern ISortAlgorithm *createTbbStableQuickSortAlgorithm(ICompare *_compare)
     return new CTbbStableQuickSortAlgorithm(_compare);
 }
 
-extern ISortAlgorithm *createInsertionSortAlgorithm(ICompare *_compare, roxiemem::IRowManager *_rowManager, unsigned _activityId)
-{
-    return new CInsertionSortAlgorithm(_compare, _rowManager, _activityId);
-}
-
 extern ISortAlgorithm *createHeapSortAlgorithm(ICompare *_compare)
 {
     return new CHeapSortAlgorithm(_compare);
@@ -1492,8 +1352,6 @@ extern ISortAlgorithm *createSortAlgorithm(RoxieSortAlgorithm _algorithm, ICompa
     {
     case heapSortAlgorithm:
         return createHeapSortAlgorithm(_compare);
-    case insertionSortAlgorithm:
-        return createInsertionSortAlgorithm(_compare, &_rowManager, _activityId);
     case quickSortAlgorithm:
         return createQuickSortAlgorithm(_compare);
     case stableQuickSortAlgorithm:

+ 1 - 2
common/thorhelper/roxiehelper.hpp

@@ -231,7 +231,7 @@ public:
 //Should be implemented in a subsequent pull request, which also uses ALGORITHM('x') instead of requiring STABLE/UNSTABLE
 typedef enum {
     heapSortAlgorithm,                  // heap sort
-    insertionSortAlgorithm,             // insertion sort - purely for comparison
+    insertionSortAlgorithm,             // insertion sort - purely for comparison (no longer supported)
     quickSortAlgorithm,                 // jlib implementation of quicksort
     stableQuickSortAlgorithm,           // jlib version of quick sort that uses an extra array indirect to ensure it is stable
     spillingQuickSortAlgorithm,         // quickSortAlgorithm with the ability to spill
@@ -260,7 +260,6 @@ extern THORHELPER_API ISortAlgorithm *createQuickSortAlgorithm(ICompare *_compar
 extern THORHELPER_API ISortAlgorithm *createStableQuickSortAlgorithm(ICompare *_compare);
 extern THORHELPER_API ISortAlgorithm *createParallelQuickSortAlgorithm(ICompare *_compare);
 extern THORHELPER_API ISortAlgorithm *createParallelStableQuickSortAlgorithm(ICompare *_compare);
-extern THORHELPER_API ISortAlgorithm *createInsertionSortAlgorithm(ICompare *_compare, roxiemem::IRowManager *_rowManager, unsigned _activityId);
 extern THORHELPER_API ISortAlgorithm *createHeapSortAlgorithm(ICompare *_compare);
 extern THORHELPER_API ISortAlgorithm *createSpillingQuickSortAlgorithm(ICompare *_compare, roxiemem::IRowManager &_rowManager, IOutputMetaData * _rowMeta, ICodeContext *_ctx, const char *_tempDirectory, unsigned _activityId, bool _stable);
 extern THORHELPER_API ISortAlgorithm *createMergeSortAlgorithm(ICompare *_compare);

+ 5 - 1
roxie/ccd/ccdfile.cpp

@@ -2695,6 +2695,9 @@ protected:
 
     void testCopy()
     {
+        remove("test.local");
+        remove("test.remote");
+        remove("test.buddy");
         CRoxieFileCache cache(true);
         StringArray remotes;
         DummyPartDescriptor pdesc;
@@ -2712,7 +2715,8 @@ protected:
 
         // Reading it should read 1
         val = 0;
-        io->read(0, sizeof(int), &val);
+        ssize_t bytesRead = io->read(0, sizeof(int), &val);
+        CPPUNIT_ASSERT(bytesRead==4);
         CPPUNIT_ASSERT(val==1);
 
         // Now create the buddy

+ 1 - 1
roxie/ccd/ccdquery.cpp

@@ -88,7 +88,7 @@ public:
     CQueryDll(const char *_dllName, ILoadedDllEntry *_dll) : dllName(_dllName), dll(_dll)
     {
         StringBuffer wuXML;
-        if (getEmbeddedWorkUnitXML(dll, wuXML))
+        if (!selfTestMode && getEmbeddedWorkUnitXML(dll, wuXML))
         {
             Owned<ILocalWorkUnit> localWU = createLocalWorkUnit(wuXML);
             wu.setown(localWU->unlock());

+ 2 - 10
roxie/ccd/ccdserver.cpp

@@ -8022,8 +8022,6 @@ public:
         }
         else if (stricmp(algorithmName, "heapsort")==0)
             sortAlgorithm = heapSortAlgorithm; // NOTE - we do allow UNSTABLE('heapsort') in order to facilitate runtime selection. Also explicit selection of heapsort overrides request to spill
-        else if (stricmp(algorithmName, "insertionsort")==0)
-            sortAlgorithm = insertionSortAlgorithm;
         else if (stricmp(algorithmName, "mergesort")==0)
             sortAlgorithm = (sortFlags & TAFspill) ? spillingMergeSortAlgorithm : mergeSortAlgorithm;
         else if (stricmp(algorithmName, "parmergesort")==0)
@@ -27537,7 +27535,6 @@ class CcdServerTest : public CppUnit::TestFixture
     CPPUNIT_TEST_SUITE(CcdServerTest);
         CPPUNIT_TEST(testSetup);
         CPPUNIT_TEST(testHeapSort);
-        CPPUNIT_TEST(testInsertionSort);
         CPPUNIT_TEST(testQuickSort);
         CPPUNIT_TEST(testMerge);
         CPPUNIT_TEST(testMergeDedup);
@@ -27555,6 +27552,7 @@ protected:
 
     void testSetup()
     {
+        selfTestMode = true;
         roxiemem::setTotalMemoryLimit(false, true, false, 100 * 1024 * 1024, 0, NULL, NULL);
     }
 
@@ -27731,8 +27729,6 @@ protected:
         sortAlgorithm = NULL;
         if (type==2)
             sortAlgorithm = "heapSort";
-        else if (type == 1)
-            sortAlgorithm = "insertionSort";
         else
             sortAlgorithm = "quickSort";
         DBGLOG("Testing %s activity", sortAlgorithm);
@@ -27841,10 +27837,6 @@ protected:
     {
         testSort(0);
     }
-    void testInsertionSort()
-    {
-        testSort(1);
-    }
     void testHeapSort()
     {
         testSort(2);
@@ -27928,7 +27920,7 @@ protected:
         unsigned start = msTick();
         testSplitActivity(factory, test, test, numOutputs, 0);
         testSplitActivity(factory, test12345, test12345, numOutputs, 0);
-        testSplitActivity(factory, test12345, test12345, numOutputs, 1000000);
+        testSplitActivity(factory, test12345, test12345, numOutputs, 100);
         unsigned elapsed = msTick() - start;
 
         DBGLOG("testSplit %d done in %dms", numOutputs, elapsed);

+ 60 - 51
roxie/roxiemem/roxiemem.cpp

@@ -5542,18 +5542,13 @@ class RoxieMemTests : public CppUnit::TestFixture
         CPPUNIT_TEST(testRoundup);
         CPPUNIT_TEST(testCompressSize);
         CPPUNIT_TEST(testBitmap);
-        CPPUNIT_TEST(testBitmapThreading);
         CPPUNIT_TEST(testAllocSize);
         CPPUNIT_TEST(testHuge);
-        CPPUNIT_TEST(testCas);
         CPPUNIT_TEST(testAll);
-        CPPUNIT_TEST(testCallbacks);
         CPPUNIT_TEST(testRecursiveCallbacks);
-        CPPUNIT_TEST(testCompacting);
         CPPUNIT_TEST(testResize);
         //MORE: The following currently leak pages, so should go last
         CPPUNIT_TEST(testDatamanager);
-        CPPUNIT_TEST(testDatamanagerThreading);
         CPPUNIT_TEST(testCleanup);
     CPPUNIT_TEST_SUITE_END();
     const IContextLogger &logctx;
@@ -5570,11 +5565,11 @@ public:
 protected:
     void testSetup()
     {
-        printf("Heaplet: cacheline(%u) base(%u) fixedbase(%u) fixed(%u) packed(%u) huge(%u)\n",
+        DBGLOG("Heaplet: cacheline(%u) base(%u) fixedbase(%u) fixed(%u) packed(%u) huge(%u)",
                 CACHE_LINE_SIZE, (size32_t)sizeof(Heaplet), (size32_t)sizeof(ChunkedHeaplet), (size32_t)sizeof(FixedSizeHeaplet), (size32_t)sizeof(PackedFixedSizeHeaplet), (size32_t)sizeof(HugeHeaplet));
-        printf("Heap: fixed(%u) packed(%u) huge(%u)\n",
+        DBGLOG("Heap: fixed(%u) packed(%u) huge(%u)",
                 (size32_t)sizeof(CFixedChunkedHeap), (size32_t)sizeof(CPackedChunkingHeap), (size32_t)sizeof(CHugeHeap));
-        printf("IHeap: fixed(%u) directfixed(%u) packed(%u) variable(%u)\n",
+        DBGLOG("IHeap: fixed(%u) directfixed(%u) packed(%u) variable(%u)",
                 (size32_t)sizeof(CRoxieFixedRowHeap), (size32_t)sizeof(CRoxieDirectFixedRowHeap), (size32_t)sizeof(CRoxieDirectPackedRowHeap), (size32_t)sizeof(CRoxieVariableRowHeap));
 
         ASSERT(FixedSizeHeaplet::dataOffset() >= sizeof(FixedSizeHeaplet));
@@ -5648,39 +5643,6 @@ protected:
         dm.cleanUp();
     }
 
-    void testDatamanagerThreading()
-    {
-        CDataBufferManager dm(DATA_ALIGNMENT_SIZE);
-
-        class casyncfor: public CAsyncFor
-        {
-        public:
-            casyncfor(CDataBufferManager &_dm) : dm(_dm) {}
-
-            void Do(unsigned idx)
-            {
-                for (unsigned j=0; j < 1000; j++)
-                {
-                    DataBuffer *pages[10000];
-                    unsigned i;
-                    for (i = 0; i < 10000; i++)
-                    {
-                        pages[i] = dm.allocate();
-                    }
-                    for (i = 0; i < 10000; i++)
-                    {
-                        pages[i]->Release();
-                    }
-                }
-            }
-        private:
-            CDataBufferManager& dm;
-        } afor(dm);
-        afor.For(5,5);
-        DBGLOG("ok");
-        dm.cleanUp();
-    }
-
     class HeapPreserver
     {
     public:
@@ -7178,6 +7140,17 @@ public:
     unsigned locks;
 };
 
+class RoxieMemTimingTests : public RoxieMemTests
+{
+    CPPUNIT_TEST_SUITE( RoxieMemTimingTests );
+        CPPUNIT_TEST(testSetup);
+        CPPUNIT_TEST(testBitmapThreading);
+        CPPUNIT_TEST(testCas);
+        CPPUNIT_TEST(testCallbacks);
+        CPPUNIT_TEST(testCompacting);
+        CPPUNIT_TEST(testCleanup);
+    CPPUNIT_TEST_SUITE_END();
+};
 
 const memsize_t memorySize = 0x60000000;
 class RoxieMemStressTests : public CppUnit::TestFixture
@@ -7189,6 +7162,7 @@ class RoxieMemStressTests : public CppUnit::TestFixture
     CPPUNIT_TEST(testResizeDoubleFragmenting);
     CPPUNIT_TEST(testResizeFragmenting);
     CPPUNIT_TEST(testSequential);
+    CPPUNIT_TEST(testDatamanagerThreading);
     CPPUNIT_TEST(testCleanup);
     CPPUNIT_TEST_SUITE_END();
     const IContextLogger &logctx;
@@ -7372,6 +7346,39 @@ protected:
         ASSERT(requestSize > memorySize/4);
     }
 
+    void testDatamanagerThreading()
+    {
+        CDataBufferManager dm(DATA_ALIGNMENT_SIZE);
+
+        class casyncfor: public CAsyncFor
+        {
+        public:
+            casyncfor(CDataBufferManager &_dm) : dm(_dm) {}
+
+            void Do(unsigned idx)
+            {
+                for (unsigned j=0; j < 1000; j++)
+                {
+                    DataBuffer *pages[1000];
+                    unsigned i;
+                    for (i = 0; i < 1000; i++)
+                    {
+                        pages[i] = dm.allocate();
+                    }
+                    for (i = 0; i < 1000; i++)
+                    {
+                        pages[i]->Release();
+                    }
+                }
+            }
+        private:
+            CDataBufferManager& dm;
+        } afor(dm);
+        afor.For(5,5);
+        DBGLOG("ok");
+        dm.cleanUp();
+    }
+
 
 };
 
@@ -7413,21 +7420,21 @@ protected:
     {
         Owned<IRowManager> rowManager = createRowManager(0, NULL, logctx, NULL);
         void * huge = rowManager->allocate(hugeAllocSize, 1);
-        ASSERT(rowManager->numPagesAfterCleanup(true)==4097);
+        ASSERT(rowManager->numPagesAfterCleanup(true)==16385);
         ReleaseRoxieRow(huge);
         ASSERT(rowManager->numPagesAfterCleanup(true)==0);
         memsize_t capacity;
         void *huge1 = rowManager->allocate(initialAllocSize, 1);
         rowManager->resizeRow(capacity, huge1, initialAllocSize, hugeAllocSize, 1);
         ASSERT(capacity > hugeAllocSize);
-        ASSERT(rowManager->numPagesAfterCleanup(true)==4097);
+        ASSERT(rowManager->numPagesAfterCleanup(true)==16385);
         ReleaseRoxieRow(huge1);
         ASSERT(rowManager->numPagesAfterCleanup(true)==0);
 
         huge1 = rowManager->allocate(hugeAllocSize/2, 1);
         rowManager->resizeRow(capacity, huge1, hugeAllocSize/2, hugeAllocSize, 1);
         ASSERT(capacity > hugeAllocSize);
-        ASSERT(rowManager->numPagesAfterCleanup(true)==4097);
+        ASSERT(rowManager->numPagesAfterCleanup(true)==16385);
         ReleaseRoxieRow(huge1);
         ASSERT(rowManager->numPagesAfterCleanup(true)==0);
 
@@ -7456,9 +7463,9 @@ static int compareTiming(const void * pLeft, const void * pRight)
 }
 
 
-class RoxieMemTuningTests : public CppUnit::TestFixture
+class RoxieMemTimingTests2 : public CppUnit::TestFixture
 {
-    CPPUNIT_TEST_SUITE( RoxieMemTuningTests );
+    CPPUNIT_TEST_SUITE( RoxieMemTimingTests2 );
     CPPUNIT_TEST(testSetup);
 #ifdef RUN_SINGLE_TEST
     CPPUNIT_TEST(testOne);
@@ -7471,11 +7478,11 @@ class RoxieMemTuningTests : public CppUnit::TestFixture
     const IContextLogger &logctx;
 
 public:
-    RoxieMemTuningTests() : logctx(queryDummyContextLogger())
+    RoxieMemTimingTests2() : logctx(queryDummyContextLogger())
     {
     }
 
-    ~RoxieMemTuningTests()
+    ~RoxieMemTimingTests2()
     {
     }
 
@@ -7604,14 +7611,16 @@ protected:
 
 CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemTests );
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemTests, "RoxieMemTests" );
+CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemTimingTests );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemTimingTests, "RoxieMemTimingTests" );
 CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemStressTests );
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemStressTests, "RoxieMemStressTests" );
 
-CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemTuningTests );
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemTuningTests, "RoxieMemTuningTests" );
+CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemTimingTests2 );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemTimingTests2, "RoxieMemTimingTests2" );
 
 #ifdef __64BIT__
-//CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemHugeTests );
+CPPUNIT_TEST_SUITE_REGISTRATION( RoxieMemHugeTests );
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RoxieMemHugeTests, "RoxieMemHugeTests" );
 #endif
 } // namespace roxiemem

+ 5 - 1
system/jlib/jfile.cpp

@@ -37,6 +37,10 @@
 #include <sys/vfs.h>
 #include <sys/sendfile.h>
 #endif
+#if defined (__APPLE__)
+#include <sys/mount.h>
+#undef MIN
+#endif
 
 #include "time.h"
 
@@ -4215,7 +4219,7 @@ extern jlib_decl offset_t getFreeSpace(const char* name)
     }
 
 
-#elif defined (__linux__)
+#elif defined (__linux__) || defined (__APPLE__)
     struct statfs buf;
     int fResult = statfs(name, &buf);
 

+ 11 - 7
testing/unittests/dalitests.cpp

@@ -439,9 +439,10 @@ void dispFDesc(IFileDescriptor *fdesc)
 
 // ================================================================================== UNIT TESTS
 
-class CDaliTests : public CppUnit::TestFixture
+class CDaliTestsStress : public CppUnit::TestFixture
 {
-    CPPUNIT_TEST_SUITE( CDaliTests );
+    CPPUNIT_TEST_SUITE( CDaliTestsStress );
+        CPPUNIT_TEST(testInit);
         CPPUNIT_TEST(testDFS);
 //        CPPUNIT_TEST(testReadAllSDS); // Ignoring this test; See comments below
         CPPUNIT_TEST(testSDSRW);
@@ -691,14 +692,17 @@ class CDaliTests : public CppUnit::TestFixture
     const IContextLogger &logctx;
 
 public:
-    CDaliTests() : logctx(queryDummyContextLogger()) {
-        init();
+    CDaliTestsStress() : logctx(queryDummyContextLogger()) {
     }
 
-    ~CDaliTests() {
+    ~CDaliTestsStress() {
         destroy();
     }
 
+    void testInit()
+    {
+        init();
+    }
     void testSDSRW()
     {
         Owned<IPropertyTree> ref = createPTree("DAREGRESS");
@@ -2361,8 +2365,8 @@ public:
 
 };
 
-CPPUNIT_TEST_SUITE_REGISTRATION( CDaliTests );
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliTests, "Dali" );
+CPPUNIT_TEST_SUITE_REGISTRATION( CDaliTestsStress );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliTestsStress, "Dali" );
 
 class CDaliUtils : public CppUnit::TestFixture
 {

+ 89 - 50
testing/unittests/jlibtests.cpp

@@ -89,12 +89,6 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibSemTest, "JlibSemTest" );
 
 class JlibSetTest : public CppUnit::TestFixture
 {
-public:
-    CPPUNIT_TEST_SUITE(JlibSetTest);
-        CPPUNIT_TEST(testBitsetHelpers);
-        CPPUNIT_TEST(testSimple);
-    CPPUNIT_TEST_SUITE_END();
-
 protected:
 
     void testBitsetHelpers()
@@ -161,28 +155,33 @@ protected:
         ASSERT((end-5) == (inclEnd-1));
     }
 
-    void testSet(bool initial)
+    void testSet(bool initial, unsigned passes, bool timed)
     {
         unsigned now = msTick();
         bool setValue = !initial;
         bool clearValue = initial;
         const unsigned numBits = 400;
-        const unsigned passes = 10000;
         for (unsigned pass=0; pass < passes; pass++)
         {
             Owned<IBitSet> bs = createThreadSafeBitSet();
             testSet1(initial, bs, 0, numBits, setValue, clearValue);
         }
-        unsigned elapsed = msTick()-now;
-        fprintf(stdout, "Bit test (%u) time taken = %dms\n", initial, elapsed);
+        if (timed)
+        {
+            unsigned elapsed = msTick()-now;
+            DBGLOG("Bit test (%u) %d passes time taken = %dms", initial, passes, elapsed);
+        }
         now = msTick();
         for (unsigned pass=0; pass < passes; pass++)
         {
             Owned<IBitSet> bs = createBitSet();
             testSet1(initial, bs, 0, numBits, setValue, clearValue);
         }
-        elapsed = msTick()-now;
-        fprintf(stdout, "Bit test [thread-unsafe version] (%u) time taken = %dms\n", initial, elapsed);
+        if (timed)
+        {
+            unsigned elapsed = msTick()-now;
+            DBGLOG("Bit test [thread-unsafe version] (%u) %d passes time taken = %dms", initial, passes, elapsed);
+        }
         now = msTick();
         size32_t bitSetMemSz = getBitSetMemoryRequirement(numBits+5);
         MemoryBuffer mb;
@@ -192,9 +191,44 @@ protected:
             Owned<IBitSet> bs = createBitSet(bitSetMemSz, mem);
             testSet1(initial, bs, 0, numBits, setValue, clearValue);
         }
-        elapsed = msTick()-now;
-        fprintf(stdout, "Bit test [thread-unsafe version, fixed memory] (%u) time taken = %dms\n", initial, elapsed);
+        if (timed)
+        {
+            unsigned elapsed = msTick()-now;
+            DBGLOG("Bit test [thread-unsafe version, fixed memory] (%u) %d passes time taken = %dms\n", initial, passes, elapsed);
+        }
     }
+};
+
+class JlibSetTestQuick : public JlibSetTest
+{
+public:
+    CPPUNIT_TEST_SUITE(JlibSetTestQuick);
+        CPPUNIT_TEST(testBitsetHelpers);
+        CPPUNIT_TEST(testSimple);
+    CPPUNIT_TEST_SUITE_END();
+
+    void testSimple()
+    {
+        testSet(false, 100, false);
+        testSet(true, 100, false);
+    }
+
+};
+
+class JlibSetTestStress : public JlibSetTest
+{
+public:
+    CPPUNIT_TEST_SUITE(JlibSetTestStress);
+        CPPUNIT_TEST(testParallel);
+        CPPUNIT_TEST(testSimple);
+    CPPUNIT_TEST_SUITE_END();
+
+    void testSimple()
+    {
+        testSet(false, 10000, true);
+        testSet(true, 10000, true);
+    }
+protected:
 
     class CBitThread : public CSimpleInterfaceOf<IInterface>, implements IThreaded
     {
@@ -326,34 +360,33 @@ protected:
         fprintf(stdout, "Thread unsafe parallel bit set test (%u) time taken = %dms\n", initial, took);
     }
 
-    void testSimple()
+    void testParallel()
     {
-        testSet(false);
-        testSet(true);
         testSetParallel(false);
         testSetParallel(true);
     }
 };
 
-CPPUNIT_TEST_SUITE_REGISTRATION( JlibSetTest );
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibSetTest, "JlibSetTest" );
+CPPUNIT_TEST_SUITE_REGISTRATION( JlibSetTestQuick );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibSetTestQuick, "JlibSetTestQuick" );
+CPPUNIT_TEST_SUITE_REGISTRATION( JlibSetTestStress );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibSetTestStress, "JlibSetTestStress" );
 
 /* =========================================================== */
-class JlibFileIOTest : public CppUnit::TestFixture
+class JlibFileIOTestTiming : public CppUnit::TestFixture
 {
+protected:
     unsigned rs, nr10pct, nr150pct;
     char *record;
     StringBuffer tmpfile;
-    StringBuffer server;
 
-    CPPUNIT_TEST_SUITE( JlibFileIOTest );
+    CPPUNIT_TEST_SUITE( JlibFileIOTestTiming );
         CPPUNIT_TEST(testIOSmall);
-        CPPUNIT_TEST(testIORemote);
         CPPUNIT_TEST(testIOLarge);
     CPPUNIT_TEST_SUITE_END();
 
 public:
-    JlibFileIOTest()
+    JlibFileIOTestTiming()
     {
         HardwareInfo hdwInfo;
         getHardwareInfo(hdwInfo);
@@ -367,17 +400,15 @@ public:
         record[rs-1] = '\n';
 
         tmpfile.set("JlibFileIOTest.txt");
-        server.set(".");
-        // server.set("192.168.1.18");
     }
 
-    ~JlibFileIOTest()
+    ~JlibFileIOTestTiming()
     {
         free(record);
     }
 
 protected:
-    void testIO(unsigned nr, SocketEndpoint *ep)
+    void testIO(unsigned nr, const char *server)
     {
         IFile *ifile;
         IFileIO *ifileio;
@@ -394,10 +425,12 @@ protected:
             else
                 fprintf(stdout, "\nFile size: %d (MB) Nocache, ", fsize);
 
-            if (ep != NULL)
+            if (server != NULL)
             {
-                ifile = createRemoteFile(*ep, tmpfile);
-                fprintf(stdout, "Remote: (%s)\n", server.str());
+                SocketEndpoint ep;
+                ep.set(server, 7100);
+                ifile = createRemoteFile(ep, tmpfile);
+                fprintf(stdout, "Remote: (%s)\n", server);
             }
             else
             {
@@ -486,31 +519,37 @@ protected:
         testIO(nr150pct, NULL);
     }
 
+
+};
+
+class JlibFileIOTestStress : public JlibFileIOTestTiming
+{
+protected:
+    CPPUNIT_TEST_SUITE( JlibFileIOTestStress );
+        CPPUNIT_TEST(testIORemote);
+    CPPUNIT_TEST_SUITE_END();
+
     void testIORemote()
     {
-        SocketEndpoint ep;
-        ep.set(server, 7100);
-        testIO(nr10pct, &ep);
+        const char * server = ".";
+        testIO(nr10pct, server);
     }
-
 };
 
-CPPUNIT_TEST_SUITE_REGISTRATION( JlibFileIOTest );
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibFileIOTest, "JlibFileIOTest" );
+CPPUNIT_TEST_SUITE_REGISTRATION( JlibFileIOTestTiming );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibFileIOTestTiming, "JlibFileIOTestTiming" );
+CPPUNIT_TEST_SUITE_REGISTRATION( JlibFileIOTestStress );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibFileIOTestTiming, "JlibFileIOTestStress" );
 
 /* =========================================================== */
 
-class JlibStringBufferTest : public CppUnit::TestFixture
+class JlibStringBufferTiming : public CppUnit::TestFixture
 {
-    CPPUNIT_TEST_SUITE( JlibStringBufferTest );
+    CPPUNIT_TEST_SUITE( JlibStringBufferTiming );
         CPPUNIT_TEST(testSwap);
     CPPUNIT_TEST_SUITE_END();
 
 public:
-    JlibStringBufferTest()
-    {
-    }
-
     void testSwap()
     {
         StringBuffer l;
@@ -525,7 +564,7 @@ public:
                 l.swapWith(r);
             }
             cycle_t elapsed = get_cycles_now() - start;
-            fprintf(stdout, "iterations of size %u took %.2f\n", len, (double)cycle_to_nanosec(elapsed) / numIter);
+            DBGLOG("Each iteration of size %u took %.2f nanoseconds", len, (double)cycle_to_nanosec(elapsed) / numIter);
             l.append("a");
             r.append("b");
         }
@@ -533,8 +572,8 @@ public:
 
 };
 
-CPPUNIT_TEST_SUITE_REGISTRATION( JlibStringBufferTest );
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibStringBufferTest, "JlibStringBufferTest" );
+CPPUNIT_TEST_SUITE_REGISTRATION( JlibStringBufferTiming );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibStringBufferTiming, "JlibStringBufferTiming" );
 
 
 
@@ -629,9 +668,9 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JlibQuantileTest, "JlibQuantileTest" );
 
 /* =========================================================== */
 
-class JlibReaderWriterTest : public CppUnit::TestFixture
+class JlibReaderWriterTestTiming : public CppUnit::TestFixture
 {
-    CPPUNIT_TEST_SUITE(JlibReaderWriterTest);
+    CPPUNIT_TEST_SUITE(JlibReaderWriterTestTiming);
     CPPUNIT_TEST(testCombinations);
     CPPUNIT_TEST_SUITE_END();
 
@@ -917,7 +956,7 @@ protected:
     unsigned unitWorkTimeMs;
 };
 
-CPPUNIT_TEST_SUITE_REGISTRATION(JlibReaderWriterTest);
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(JlibReaderWriterTest, "JlibReaderWriterTest");
+CPPUNIT_TEST_SUITE_REGISTRATION(JlibReaderWriterTestTiming);
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(JlibReaderWriterTestTiming, "JlibReaderWriterTestTiming");
 
 #endif // _USE_CPPUNIT

+ 197 - 16
testing/unittests/unittests.cpp

@@ -18,6 +18,8 @@
 #ifdef _USE_CPPUNIT
 #include "unittests.hpp"
 #include "jstats.h"
+#include "jregexp.hpp"
+#include "jfile.hpp"
 
 /*
  * This is the main unittest driver for HPCC. From here,
@@ -37,34 +39,213 @@
  * CPPUnit will automatically recognise and run them all.
  */
 
+void usage()
+{
+    printf("\n"
+    "Usage:\n"
+    "    unittests <options> <testnames>\n"
+    "\n"
+    "Options:\n"
+    "    -a  --all        Include all tests, including timing and stress tests\n"
+    "    -d  --load path  Dynamically load a library/all libraries in a directory.\n"
+    "                     By default, the HPCCSystems lib directory is loaded.\n"
+    "    -e  --exact      Match subsequent test names exactly\n"
+    "    -h  --help       Display this help text\n"
+    "    -l  --list       List matching tests but do not execute them\n"
+    "    -x  --exclude    Exclude subsequent test names\n"
+    "\n");
+}
+
+bool matchName(const char *name, const StringArray &patterns)
+{
+    ForEachItemIn(idx, patterns)
+    {
+        bool match;
+        const char *pattern = patterns.item(idx);
+        if (strchr(pattern, '*'))
+        {
+            match = WildMatch(name, pattern, true);
+        }
+        else
+            match = streq(name, pattern);
+        if (match)
+            return true;
+    }
+    return false;
+}
+
+LoadedObject *loadDll(const char *thisDll)
+{
+    try
+    {
+        DBGLOG("Loading %s", thisDll);
+        return new LoadedObject(thisDll);
+    }
+    catch (IException *E)
+    {
+        E->Release();
+    }
+    catch (...)
+    {
+    }
+    return NULL;
+}
+
+void loadDlls(IArray &objects, const char * libDirectory)
+{
+    const char * mask = "*" SharedObjectExtension;
+    Owned<IFile> libDir = createIFile(libDirectory);
+    Owned<IDirectoryIterator> libFiles = libDir->directoryFiles(mask,false,false);
+    ForEach(*libFiles)
+    {
+        const char *thisDll = libFiles->query().queryFilename();
+        if (!strstr(thisDll, "javaembed"))  // Bit of a hack, but loading this if java not present terminates...
+        {
+            LoadedObject *loaded = loadDll(thisDll);
+            if (loaded)
+                objects.append(*loaded);
+        }
+    }
+}
+
 int main(int argc, char* argv[])
 {
     InitModuleObjects();
-    // These are the internal unit tests covered by other modules and libraries
-    IArray 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)
+    StringArray includeNames;
+    StringArray excludeNames;
+    StringArray loadLocations;
+    bool wildMatch = true;
+    bool exclude = false;
+    bool includeAll = false;
+    bool verbose = false;
+    bool list = false;
+    bool useDefaultLocations = true;
+    for (int argNo = 1; argNo < argc; argNo++)
     {
-        CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
-        runner.addTest( registry.makeTest() );
+        const char *arg = argv[argNo];
+        if (arg[0]=='-')
+        {
+            if (streq(arg, "-x") || streq(arg, "--exclude"))
+                exclude = true;
+            else if (streq(arg, "-v") || streq(arg, "--verbose"))
+                verbose = true;
+            else if (streq(arg, "-e") || streq(arg, "--exact"))
+                wildMatch = false;
+            else if (streq(arg, "-a") || streq(arg, "--all"))
+                includeAll = true;
+            else if (streq(arg, "-l") || streq(arg, "--list"))
+                list = true;
+            else if (streq(arg, "-d") || streq(arg, "--load"))
+            {
+                useDefaultLocations = false;
+                argNo++;
+                if (argNo<argc)
+                   loadLocations.append(argv[argNo]);
+            }
+            else
+            {
+                usage();
+                exit(streq(arg, "-h") || streq(arg, "--help")?0:4);
+            }
+        }
+        else
+        {
+            VStringBuffer pattern("*%s*", arg);
+            if (wildMatch && !strchr(arg, '*'))
+                arg = pattern.str();
+            if (exclude)
+                excludeNames.append(arg);
+            else
+                includeNames.append(arg);
+        }
     }
-    else 
+    if (verbose)
+        queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_time);
+    else
+        removeLog();
+
+    if (!includeNames.length())
+        includeNames.append("*");
+
+    if (!includeAll)
     {
-        for (int name = 1; name < argc; name++)
+        excludeNames.append("*stress*");
+        excludeNames.append("*timing*");
+    }
+
+    if (useDefaultLocations)
+    {
+        // Default library location depends on the executable location...
+        StringBuffer dir;
+        splitFilename(argv[0], &dir, &dir, NULL, NULL);
+        dir.replaceString(PATHSEPSTR "bin" PATHSEPSTR, PATHSEPSTR "lib" PATHSEPSTR);
+        if (verbose)
+            DBGLOG("Adding default library location %s", dir.str());
+        loadLocations.append(dir);
+#ifdef _DEBUG
+        dir.replaceString(PATHSEPSTR "lib" PATHSEPSTR, PATHSEPSTR "libs" PATHSEPSTR);
+        loadLocations.append(dir);
+        if (verbose)
+            DBGLOG("Adding default library location %s", dir.str());
+#endif
+    }
+    IArray objects;
+    ForEachItemIn(idx, loadLocations)
+    {
+        const char *location = loadLocations.item(idx);
+        Owned<IFile> file = createIFile(location);
+        switch (file->isDirectory())
+        {
+        case notFound:
+            if (verbose && !useDefaultLocations)
+                DBGLOG("Specified library location %s not found", location);
+            break;
+        case foundYes:
+            loadDlls(objects, location);
+            break;
+        case foundNo:
+            LoadedObject *loaded = loadDll(location);
+            if (loaded)
+                objects.append(*loaded);
+            break;
+        }
+    }
+
+    bool wasSuccessful = false;
+    {
+        // New scope as we need the TestRunner to be destroyed before unloading the dlls...
+        CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
+        CppUnit::TextUi::TestRunner runner;
+        CppUnit::Test *all = registry.makeTest();
+        int numTests = all->getChildTestCount();
+        for (int i = 0; i < numTests; i++)
         {
-            CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry(argv[name]);
-            runner.addTest( registry.makeTest() );
+            CppUnit::Test *sub = all->getChildTestAt(i);
+            std::string name = sub->getName();
+            if (matchName(name.c_str(), includeNames))
+            {
+                if (matchName(name.c_str(), excludeNames))
+                {
+                    if (verbose)
+                        DBGLOG("Excluding test %s", name.c_str());
+                }
+                else if (list)
+                    printf("%s\n", name.c_str());
+                else
+                {
+                    if (verbose)
+                        DBGLOG("Including test %s", name.c_str());
+                    runner.addTest(sub);
+                }
+            }
         }
+        wasSuccessful = list || runner.run( "", false );
     }
-    bool wasSucessful = runner.run( "", false );
+    objects.kill();
     ExitModuleObjects();
     releaseAtoms();
-    return wasSucessful;
+    return wasSuccessful;
 }