[mapguide-commits] r9599 - trunk/MgDev/Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Sep 11 00:21:40 PDT 2019


Author: jng
Date: 2019-09-11 00:21:40 -0700 (Wed, 11 Sep 2019)
New Revision: 9599

Modified:
   trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp
   trunk/MgDev/Server/src/UnitTesting/TestMisc.h
Log:
#2401: Add multi-threaded MgConfiguration access test to verify that GetBoolValue is indeed thread-safe

Modified: trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp	2019-09-02 11:51:01 UTC (rev 9598)
+++ trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp	2019-09-11 07:21:40 UTC (rev 9599)
@@ -25,7 +25,12 @@
 #include "FdoConnectionManager.h"
 
 const STRING TEST_LOCALE = L"en";
+static const INT32 MG_TEST_THREADS = 16;
 
+// define thread group for config tests
+#define THREAD_GROUP 65520
+#define TESTREQUESTS 5000
+
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestMisc, "TestMisc");
 
 TestMisc::TestMisc()
@@ -771,4 +776,140 @@
     {
         throw;
     }
+}
+
+// data structure which is passed to each thread
+struct GetConfigValueThreadData
+{
+    INT32 threadId;
+    bool success;
+    bool done;
+    STRING section;
+    STRING key;
+};
+
+ACE_THR_FUNC_RETURN GetConfigValueWorker(void* param)
+{
+    // get the data for this thread
+    GetConfigValueThreadData* threadData = (GetConfigValueThreadData*)param;
+    INT32 threadId = threadData->threadId;
+#ifdef _DEBUG
+    printf("> thread %d started, tile %d,%d\n", threadId, tileRow, tileCol);
+#endif
+
+    try
+    {
+        MgConfiguration* conf = MgConfiguration::GetInstance();
+        bool b = false;
+        conf->GetBoolValue(threadData->section, threadData->key, b, false);
+
+        threadData->success = true;
+    }
+    catch (MgException* e)
+    {
+        threadData->success = false;
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        threadData->success = false;
+        throw;
+    }
+
+#ifdef _DEBUG
+    //  printf("> thread %d done\n", threadId);
+#endif
+
+    threadData->done = true;
+    return 0;
+}
+
+void TestMisc::TestCase_ThreadSafeConfiguration()
+{
+    try
+    {
+        // specify the number of threads to use
+        const INT32 numThreads = MG_TEST_THREADS;
+        GetConfigValueThreadData threadData[numThreads];
+
+        // need a thread manager
+        ACE_Thread_Manager* manager = ACE_Thread_Manager::instance();
+
+        // initialize the thread data
+        for (INT32 i = 0; i < numThreads; i++)
+        {
+            threadData[i].threadId = i;
+            threadData[i].done = true;
+            threadData[i].success = true;
+            threadData[i].section = MgConfigProperties::GeneralPropertiesSection;
+            threadData[i].key = MgConfigProperties::GeneralPropertyMaxLogFileSizeEnabled;
+        }
+
+        INT32 nRequest = 0;
+        INT32 nSuccessful = 0;
+        INT32 nFailed = 0;
+        bool bExceptionOcurred = false;
+        for (;;)
+        {
+            INT32 dc = 0;
+            for (INT32 i = 0; i < numThreads; i++)
+            {
+                // check if the thread is available
+                if (threadData[i].done)
+                {
+                    if (threadData[i].success)
+                        nSuccessful++;
+                    else
+                        nFailed++;
+
+                    // Reset for next run
+                    threadData[i].success = true;
+                    threadData[i].done = false;
+
+                    // spawn a new thread using a specific group id
+                    int thid = manager->spawn(ACE_THR_FUNC(GetConfigValueWorker), &threadData[i], 0, NULL, NULL, 0, THREAD_GROUP);
+                    nRequest++;
+                }
+            }
+
+            // move on if all threads are done
+            if ((nRequest > TESTREQUESTS) || (bExceptionOcurred))
+                break;
+
+            // under Linux we get a deadlock if we don't call this every once in a while
+            if (nRequest % 25 == 0)
+                manager->wait_grp(THREAD_GROUP);
+            else
+            {
+                // pause briefly (10ms) before checking again
+                ACE_Time_Value t(0, 10000);
+                ACE_OS::sleep(t);
+            }
+        }
+
+        // make sure all threads in the group have completed
+        manager->wait_grp(THREAD_GROUP);
+
+        for (INT32 i = 0; i < numThreads; i++)
+        {
+            if (threadData[i].success)
+                nSuccessful++;
+            else
+                nFailed++;
+        }
+
+        CPPUNIT_ASSERT(nFailed == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
 }
\ No newline at end of file

Modified: trunk/MgDev/Server/src/UnitTesting/TestMisc.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMisc.h	2019-09-02 11:51:01 UTC (rev 9598)
+++ trunk/MgDev/Server/src/UnitTesting/TestMisc.h	2019-09-11 07:21:40 UTC (rev 9599)
@@ -34,6 +34,7 @@
     CPPUNIT_TEST(TestCase_DoubleToStringWithDecimals);
     CPPUNIT_TEST(TestCase_TryParseDouble);
     CPPUNIT_TEST(TestCase_BadResourceIdentifier);
+    CPPUNIT_TEST(TestCase_ThreadSafeConfiguration);
 
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
@@ -57,6 +58,7 @@
     void TestCase_DoubleToStringWithDecimals();
     void TestCase_TryParseDouble();
     void TestCase_BadResourceIdentifier();
+    void TestCase_ThreadSafeConfiguration();
 
 private:
     Ptr<MgSiteConnection> m_siteConnection;



More information about the mapguide-commits mailing list