Add RUNNER_PERF_TEST_BEGIN() and RUNNER_PERF_TEST_END() macros for performance tests 44/18944/7 accepted/tizen_3.0.2014.q3_common accepted/tizen_3.0.m14.3_ivi accepted/tizen_3.0_common accepted/tizen_3.0_ivi accepted/tizen_common accepted/tizen_ivi accepted/tizen_mobile accepted/tizen_tv accepted/tizen_wearable tizen_3.0.2014.q3_common tizen_3.0.2014.q4_common tizen_3.0.2015.q1_common tizen_3.0.2015.q2_common tizen_3.0.m14.2_ivi tizen_3.0.m14.3_ivi tizen_3.0.m1_mobile tizen_3.0.m1_tv tizen_3.0.m2 tizen_3.0_ivi accepted/tizen/3.0/common/20161114.110355 submit/tizen_3.0_common/20161104.104000 submit/tizen_common/20140521.163740 submit/tizen_common/20140522.130648 submit/tizen_common/20140522.135644 submit/tizen_common/20151023.083358 submit/tizen_common/20151026.085049 submit/tizen_ivi/20140618.000001 submit/tizen_ivi/20140618.000004 submit/tizen_ivi/20140619.000000 submit/tizen_ivi/20140622.000000 submit/tizen_ivi/20140623.000000 submit/tizen_ivi/20140624.064036 submit/tizen_ivi/20140626.125712 submit/tizen_ivi/20140626.130032 submit/tizen_ivi/20140626.144348 submit/tizen_mobile/20141120.000000 tizen_3.0.2014.q3_common_release tizen_3.0.m14.2_ivi_release tizen_3.0.m14.3_ivi_release tizen_3.0.m1_mobile_release tizen_3.0.m1_tv_release tizen_3.0_ivi_release
authorJanusz Kozerski <j.kozerski@samsung.com>
Thu, 12 Dec 2013 10:37:41 +0000 (11:37 +0100)
committerSoo-Hyun Choi <s.choi@hackerslab.eu>
Wed, 16 Apr 2014 06:06:39 +0000 (23:06 -0700)
Added RUNNER_PERF_TEST_BEGIN(max_time) and RUNNER_PERF_TEST_END() macros.
    Add both of these macros in test when you want to do the time measurement.
The first macro is used to start the time measurement, the second is used to
end the measuement. The result will be displayed if and only if the test will
pass. RUNNER_PERF_TEST_BEGIN(time), takes one parameter (type of double) - the
expected time. If the measured time will be shorter than expected then result
will be print in console in green color, otherwise the result will be print
in red. If other output method will be choosen then measured time and max time
(if defined) will be displayed. In TAP output format there is no preformance
results. If you don't want to give any param as the expected time then put 0 or
any negative value (any value <= 0) as a param (RUNNER_PERF_TEST_BEGIN(0)) and
the param will be ignored. In that case the result in console will be always
printed in white.
    The precision of measurement is 1 microsecond - the smallest time value
that can be measured is 0.000001s.

Remarks:
 * The result of time measurement will be displayed only if the test will pass.
 * Make sure that you use each of these macros at most ONCE in each test. In
      the other case the result of first measurement will be overrwriten by the
      second.
 * Make sure that you use macros in right order.
 * In case of RUNNER_MULTIPROCESS_TEST the time measurement will wokrs only if
      the macors will be used in parent process. If you will use these macros
      in the child code then you will see no result.
 * The performance results will be displayed only in these output format:
      - text
      - html
      - xml
      - csv

[Problem]  No framework for performance tests
[Cause]    N/A
[Solution] Added RUNNER_PERF_TEST_BEGIN(expected_time) and RUNNER_PERF_TEST_END()
           macros.
[Verification] Add these macros to a few passing tests and a few failing tests,
               and check if results are displayed correctly.

Change-Id: I9eebaade094fbdf1d2af34e7da2871b7307f89c6
Signed-off-by: Janusz Kozerski <j.kozerski@samsung.com>
modules/test/include/dpl/test/test_results_collector.h
modules/test/include/dpl/test/test_runner.h
modules/test/include/dpl/test/test_runner_child.h
modules/test/src/test_results_collector.cpp
modules/test/src/test_runner.cpp
modules/test/src/test_runner_child.cpp

index 73fe1bf..cb29921 100644 (file)
@@ -27,6 +27,7 @@
 #include <vector>
 #include <list>
 #include <map>
+#include <chrono>
 #include <string>
 #include <memory>
 
@@ -68,7 +69,10 @@ class TestResultsCollectorBase :
     virtual void CollectResult(const std::string& id,
                                const std::string& description,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "") = 0;
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = false,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) = 0;
     virtual std::string CollectorSpecificHelp() const
     {
         return "";
index 6cd948f..53327a4 100644 (file)
@@ -30,6 +30,7 @@
 #include <sstream>
 #include <string>
 #include <vector>
+#include <chrono>
 #include <list>
 #include <set>
 #include <map>
@@ -47,10 +48,20 @@ class TestRunner
 
   public:
     TestRunner() :
-        m_terminate(false)
+        m_currentTestCase(NULL)
+      , m_terminate(false)
       , m_allowChildLogs(false)
     {}
 
+    void beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds);
+    void endPerformanceTestTime();
+    void getCurrentTestCasePerformanceResult(bool& isPerformanceTest,
+                                             std::chrono::system_clock::duration& result,
+                                             std::chrono::system_clock::duration& resultMax);
+    void setCurrentTestCasePerformanceResult(bool isPerformanceTest,
+                                             std::chrono::system_clock::duration result,
+                                             std::chrono::system_clock::duration resultMax);
+
     typedef void (*TestCase)();
 
   private:
@@ -59,6 +70,11 @@ class TestRunner
         std::string name;
         TestCase proc;
 
+        bool m_isPerformanceTest;
+        std::chrono::system_clock::time_point m_performanceTestStartTime;
+        std::chrono::system_clock::duration m_performanceTestDurationTime;
+        std::chrono::system_clock::duration m_performanceMaxTime;
+
         bool operator <(const TestCaseStruct &other) const
         {
             return name < other.name;
@@ -71,7 +87,8 @@ class TestRunner
 
         TestCaseStruct(const std::string &n, TestCase p) :
             name(n),
-            proc(p)
+            proc(p),
+            m_isPerformanceTest(false)
         {}
     };
 
@@ -79,6 +96,8 @@ class TestRunner
     typedef std::map<std::string, TestCaseStructList> TestCaseGroupMap;
     TestCaseGroupMap m_testGroups;
 
+    TestCaseStruct * m_currentTestCase;
+
     typedef std::set<std::string> SelectedTestNameSet;
     SelectedTestNameSet m_selectedTestNamesSet;
     typedef std::set<std::string> SelectedTestGroupSet;
@@ -105,13 +124,19 @@ class TestRunner
 
     Status RunTestCase(const TestCaseStruct& testCase);
 
+    void setCurrentTestCase(TestCaseStruct* testCase);
+    TestCaseStruct *getCurrentTestCase();
+
     void RunTests();
 
     void CollectResult(const std::string& id,
                        const std::string& description,
                        const TestResultsCollectorBase::FailStatus::Type status
                            = TestResultsCollectorBase::FailStatus::NONE,
-                       const std::string& reason = std::string());
+                       const std::string& reason = std::string(),
+                       const bool& isPerformanceTest = false,
+                       const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                       const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero());
 
   public:
     class TestFailed
@@ -226,4 +251,32 @@ typedef DPL::Singleton<TestRunner> TestRunnerSingleton;
                                                    assertMsg.str()); \
 } while (0)
 
+/*
+ * Use these macros to do the time measurement. The first macro will start time measurement,
+ * the second will gather the result. These macros can be used only once per test-case.
+ * The result of time measurement will be displayed only if the test will pass.
+ * Notice that these macros will work only if will be used in parent process. If these
+ * macros will be used in child process then there will be no time measure results printed.
+ * This macro in multiprocess tests has effect only if used in parent process. This macro
+ * used in child process in multiprocess test has no effect.
+ * The precision of measurement is 1 microsecond - the smallest time value that can be
+ * measured is 0.000001s.
+ * The time measure results will be printed only specific output format:
+ *     - text
+ *     - html
+ *     - xml
+ *     - csv
+ * In TAP format performance result will not be displayed.
+ */
+#define RUNNER_PERF_TEST_BEGIN(maxTime)                                        \
+    do {                                                                       \
+        DPL::Test::TestRunnerSingleton::Instance().beginPerformanceTestTime(   \
+                std::chrono::microseconds{static_cast<long long int>(maxTime*1000000.0)}); \
+    } while (0)
+
+#define RUNNER_PERF_TEST_END()                                                \
+    do {                                                                      \
+        DPL::Test::TestRunnerSingleton::Instance().endPerformanceTestTime();  \
+    } while (0)
+
 #endif // DPL_TEST_RUNNER_H
index 1da0f1b..d1e4b1c 100644 (file)
@@ -50,14 +50,23 @@ class PipeWrapper : DPL::Noncopyable
     virtual ~PipeWrapper();
 
     Status send(int code, std::string &message);
+    Status sendTime(int code,
+                    std::chrono::system_clock::duration time,
+                    std::chrono::system_clock::duration timeMax);
 
-    Status receive(int &code, std::string &data, time_t deadline);
+    Status receive(int &code,
+                   int &msgType,
+                   std::string &data,
+                   std::chrono::system_clock::duration &time,
+                   std::chrono::system_clock::duration &timeMax,
+                   time_t deadline);
 
     void closeAll();
 
   protected:
 
     std::string toBinaryString(int data);
+    std::string toBinaryString(std::chrono::system_clock::duration data);
 
     void closeHelp(int desc);
 
index 025dd84..beefc17 100644 (file)
@@ -21,6 +21,7 @@
  */
 #include <cstddef>
 #include <dpl/test/test_results_collector.h>
+#include <dpl/availability.h>
 #include <dpl/colors.h>
 #include <dpl/assert.h>
 #include <dpl/foreach.h>
 
 #define GREEN_RESULT_OK "[%s%s%s]\n", BOLD_GREEN_BEGIN, "   OK   ", \
     BOLD_GREEN_END
+#define GREEN_RESULT_OK_TIME "[%s%s%s] [elapsed: %0.3fms]\n", BOLD_GREEN_BEGIN, \
+    "   OK   ", BOLD_GREEN_END
+#define GREEN_RESULT_OK_TIME_MAX(elapsed, max) \
+    "[%s%s%s] %s[elapsed: %0.3fms, expected < %0.3fms]%s\n", BOLD_GREEN_BEGIN, \
+    "   OK   ", BOLD_GREEN_END, BOLD_GREEN_BEGIN, elapsed, max, BOLD_GREEN_END
+#define GREEN_RESULT_OK_TIME_TOO_LONG(elapsed, max) \
+    "[%s%s%s] %s[elapsed: %0.3fms, expected < %0.3fms]%s\n", BOLD_GREEN_BEGIN, \
+    "   OK   ", BOLD_GREEN_END, BOLD_RED_BEGIN, elapsed, max, BOLD_RED_END
+
+namespace { /* anonymous namespace */
+// Get duration as a fraction of millisecond (max precision is 1 microsecond)
+double get_milliseconds (const std::chrono::system_clock::duration& performanceTime)
+{
+    return (static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>
+            (performanceTime).count()))/1000.0;
+}
+} /* anonymous namespace */
 
 namespace DPL {
 namespace Test {
@@ -146,7 +164,10 @@ class ConsoleCollector :
     virtual void CollectResult(const std::string& id,
                                const std::string& /*description*/,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "")
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = true,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero())
     {
         using namespace DPL::Colors::Text;
         std::string tmp = "'" + id + "' ...";
@@ -154,6 +175,24 @@ class ConsoleCollector :
         printf("Running test case %-60s", tmp.c_str());
         switch (status) {
         case TestResultsCollectorBase::FailStatus::NONE:
+            if (isPerformanceTest) {
+                if (performanceMaxTime <= std::chrono::microseconds::zero()) {
+                    printf(GREEN_RESULT_OK_TIME,
+                            get_milliseconds(performanceTime));
+                    break;
+                }
+                else {
+                    if (performanceTime > performanceMaxTime)
+                        printf(GREEN_RESULT_OK_TIME_TOO_LONG(
+                                get_milliseconds(performanceTime),
+                                get_milliseconds(performanceMaxTime)));
+                    else
+                        printf(GREEN_RESULT_OK_TIME_MAX(
+                                get_milliseconds(performanceTime),
+                                get_milliseconds(performanceMaxTime)));
+                    break;
+                }
+            }
             printf(GREEN_RESULT_OK);
             break;
         case TestResultsCollectorBase::FailStatus::FAILED:
@@ -319,7 +358,10 @@ class HtmlCollector :
     virtual void CollectResult(const std::string& id,
                                const std::string& /*description*/,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "")
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = false,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero())
     {
         using namespace DPL::Colors::Html;
         std::string tmp = "'" + id + "' ...";
@@ -327,6 +369,23 @@ class HtmlCollector :
         fprintf(m_fp.Get(), "Running test case %-100s", tmp.c_str());
         switch (status) {
         case TestResultsCollectorBase::FailStatus::NONE:
+            if (isPerformanceTest) {
+                if (performanceMaxTime <= std::chrono::microseconds::zero()) {
+                    fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME,
+                            get_milliseconds(performanceTime));
+                    break;
+                } else {
+                    if (performanceTime > performanceMaxTime)
+                        fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_TOO_LONG(
+                                get_milliseconds(performanceTime),
+                                get_milliseconds(performanceMaxTime)));
+                    else
+                        fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_MAX(
+                                get_milliseconds(performanceTime),
+                                get_milliseconds(performanceMaxTime)));
+                    break;
+                }
+            }
             fprintf(m_fp.Get(), GREEN_RESULT_OK);
             break;
         case TestResultsCollectorBase::FailStatus::FAILED:
@@ -510,7 +569,10 @@ class XmlCollector :
     virtual void CollectResult(const std::string& id,
                                const std::string& /*description*/,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "")
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = false,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero())
     {
         m_resultBuffer.erase();
         m_resultBuffer.append("\t\t<testcase name=\"");
@@ -518,6 +580,27 @@ class XmlCollector :
         m_resultBuffer.append("\"");
         switch (status) {
         case TestResultsCollectorBase::FailStatus::NONE:
+            if (isPerformanceTest) {
+                if (performanceMaxTime <= std::chrono::microseconds::zero()) {
+                    m_resultBuffer.append(" status=\"OK\" time=\"");
+                    std::ostringstream ostr;
+                    ostr << performanceTime.count();
+                    m_resultBuffer.append(ostr.str());
+                    m_resultBuffer.append("\"/>\n");
+                    break;
+                } else {
+                    m_resultBuffer.append(" status=\"OK\" time=\"");
+                    std::ostringstream ostr;
+                    ostr << performanceTime.count();
+                    m_resultBuffer.append(ostr.str());
+                    m_resultBuffer.append("\" time_expected=\"");
+                    ostr.str("");
+                    ostr << performanceMaxTime.count();
+                    m_resultBuffer.append(ostr.str());
+                    m_resultBuffer.append("\"/>\n");
+                    break;
+                }
+            }
             m_resultBuffer.append(" status=\"OK\"/>\n");
             break;
         case TestResultsCollectorBase::FailStatus::FAILED:
@@ -763,7 +846,7 @@ class CSVCollector :
 
     virtual void Start()
     {
-        printf("GROUP;ID;RESULT;REASON\n");
+        printf("GROUP;ID;RESULT;REASON;ELAPSED [s];EXPECTED [s]\n");
     }
 
     virtual void CollectCurrentTestGroupName(const std::string& name)
@@ -774,11 +857,27 @@ class CSVCollector :
     virtual void CollectResult(const std::string& id,
                                const std::string& /*description*/,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "")
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = false,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero())
     {
         std::string statusMsg = "";
         switch (status) {
-        case TestResultsCollectorBase::FailStatus::NONE: statusMsg = "OK";
+        case TestResultsCollectorBase::FailStatus::NONE:
+            statusMsg = "OK";
+            if (isPerformanceTest) {
+                statusMsg.append(";;");
+                std::ostringstream ostr;
+                ostr << performanceTime.count();
+                statusMsg.append(ostr.str());
+                if (performanceMaxTime <= std::chrono::microseconds::zero()) {
+                    statusMsg.append(";");
+                    ostr.str("");
+                    ostr << performanceMaxTime.count();
+                    statusMsg.append(ostr.str());
+                }
+            }
             break;
         case TestResultsCollectorBase::FailStatus::FAILED: statusMsg = "FAILED";
             break;
@@ -856,8 +955,16 @@ class TAPCollector :
     virtual void CollectResult(const std::string& id,
                                const std::string& description,
                                const FailStatus::Type status = FailStatus::NONE,
-                               const std::string& reason = "")
+                               const std::string& reason = "",
+                               const bool& isPerformanceTest = false,
+                               const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(),
+                               const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero())
     {
+        /* Remove unused variable warning */
+        DPL_UNUSED_PARAM(isPerformanceTest);
+        DPL_UNUSED_PARAM(performanceTime);
+        DPL_UNUSED_PARAM(performanceMaxTime);
+
         m_testIndex++;
         switch (status) {
         case TestResultsCollectorBase::FailStatus::NONE:
index 594ba0c..f9a6f4c 100644 (file)
@@ -247,6 +247,7 @@ bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap)
 
 TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
 {
+    setCurrentTestCase(&(const_cast<TestCaseStruct &>(testCase)));
     try {
         testCase.proc();
     } catch (const TestFailed &e) {
@@ -255,6 +256,8 @@ TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
                       "",
                       TestResultsCollectorBase::FailStatus::FAILED,
                       e.GetMessage());
+
+        setCurrentTestCase(NULL);
         return FAILED;
     } catch (const Ignored &e) {
         if (m_runIgnored) {
@@ -265,6 +268,7 @@ TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
                           e.GetMessage());
         }
 
+        setCurrentTestCase(NULL);
         return IGNORED;
     } catch (const DPL::Exception &e) {
         // DPL exception failure
@@ -273,6 +277,7 @@ TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
                       TestResultsCollectorBase::FailStatus::INTERNAL,
                       "DPL exception:" + e.GetMessage());
 
+        setCurrentTestCase(NULL);
         return FAILED;
     } catch (const std::exception &) {
         // std exception failure
@@ -281,6 +286,7 @@ TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
                       TestResultsCollectorBase::FailStatus::INTERNAL,
                       "std exception");
 
+        setCurrentTestCase(NULL);
         return FAILED;
     } catch (...) {
         // Unknown exception failure
@@ -289,12 +295,18 @@ TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
                       TestResultsCollectorBase::FailStatus::INTERNAL,
                       "unknown exception");
 
+        setCurrentTestCase(NULL);
         return FAILED;
     }
 
     CollectResult(testCase.name,
                   "",
-                  TestResultsCollectorBase::FailStatus::NONE);
+                  TestResultsCollectorBase::FailStatus::NONE,
+                  "",
+                  testCase.m_isPerformanceTest,
+                  testCase.m_performanceTestDurationTime,
+                  testCase.m_performanceMaxTime);
+    setCurrentTestCase(NULL);
 
     // Everything OK
     return PASS;
@@ -362,11 +374,77 @@ void TestRunner::RunTests()
     fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END);
 }
 
+TestRunner::TestCaseStruct *TestRunner::getCurrentTestCase()
+{
+    return m_currentTestCase;
+}
+
+void TestRunner::setCurrentTestCase(TestCaseStruct* testCase)
+{
+    m_currentTestCase = testCase;
+}
+
+void TestRunner::beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds)
+{
+    TestCaseStruct* testCase = getCurrentTestCase();
+    if (!testCase)
+        return;
+
+    testCase->m_isPerformanceTest = true;
+    testCase->m_performanceMaxTime = maxTimeInMicroseconds;
+    testCase->m_performanceTestStartTime = std::chrono::system_clock::now();
+
+    // Set result to 0 microseconds. Display 0ms result when end macro is missing.
+    testCase->m_performanceTestDurationTime = std::chrono::microseconds::zero();
+}
+
+void TestRunner::endPerformanceTestTime()
+{
+    TestCaseStruct* testCase = getCurrentTestCase();
+    if (!testCase)
+        return;
+
+    testCase->m_performanceTestDurationTime = std::chrono::system_clock::now() -
+            testCase->m_performanceTestStartTime;
+}
+
+void TestRunner::getCurrentTestCasePerformanceResult(bool& isPerformanceTest,
+                                                     std::chrono::system_clock::duration& result,
+                                                     std::chrono::system_clock::duration& resultMax)
+{
+    TestCaseStruct* testCase = getCurrentTestCase();
+    if (!testCase || !(testCase->m_isPerformanceTest)){
+        isPerformanceTest = false;
+        return;
+    }
+
+    isPerformanceTest = testCase->m_isPerformanceTest;
+    result = testCase->m_performanceTestDurationTime;
+    resultMax = testCase->m_performanceMaxTime;
+}
+
+void TestRunner::setCurrentTestCasePerformanceResult(bool isPerformanceTest,
+                                                     std::chrono::system_clock::duration result,
+                                                     std::chrono::system_clock::duration resultMax)
+{
+    TestCaseStruct* testCase = getCurrentTestCase();
+    if (!testCase)
+        return;
+
+    testCase->m_isPerformanceTest = isPerformanceTest;
+    testCase->m_performanceTestDurationTime = result;
+    testCase->m_performanceMaxTime = resultMax;
+}
+
+
 void TestRunner::CollectResult(
     const std::string& id,
     const std::string& description,
     const TestResultsCollectorBase::FailStatus::Type status,
-    const std::string& reason)
+    const std::string& reason,
+    const bool& isPerformanceTest,
+    const std::chrono::system_clock::duration& performanceTestDurationTime,
+    const std::chrono::system_clock::duration& performanceMaxTime)
 {
     std::for_each(m_collectors.begin(),
                   m_collectors.end(),
@@ -375,7 +453,10 @@ void TestRunner::CollectResult(
                       collector.second->CollectResult(id,
                                                       description,
                                                       status,
-                                                      reason);
+                                                      reason,
+                                                      isPerformanceTest,
+                                                      performanceTestDurationTime,
+                                                      performanceMaxTime);
                   });
 }
 
index 8e793e8..a8840fc 100644 (file)
@@ -49,6 +49,9 @@ const int CHILD_TEST_FAIL    = 0;
 const int CHILD_TEST_PASS    = 1;
 const int CHILD_TEST_IGNORED = 2;
 
+const int MSG_TYPE_MESSAGE   = 0; // sizeof(Message) + Message
+const int MSG_TYPE_PERF_TIME = 1; // perfTime + maxTime
+
 int closeOutput() {
     int devnull;
     int retcode = -1;
@@ -112,6 +115,7 @@ PipeWrapper::Status PipeWrapper::send(int code, std::string &message)
 
     std::ostringstream output;
     output << toBinaryString(code);
+    output << toBinaryString(MSG_TYPE_MESSAGE);
     output << toBinaryString(static_cast<int>(message.size()));
     output << message;
 
@@ -127,7 +131,38 @@ PipeWrapper::Status PipeWrapper::send(int code, std::string &message)
     return SUCCESS;
 }
 
-PipeWrapper::Status PipeWrapper::receive(int &code, std::string &data, time_t deadline)
+PipeWrapper::Status PipeWrapper::sendTime(int code,
+                                          std::chrono::system_clock::duration time,
+                                          std::chrono::system_clock::duration timeMax)
+{
+    if (m_pipefd[1] == PIPE_CLOSED) {
+        return ERROR;
+    }
+
+    std::ostringstream output;
+    output << toBinaryString(code);
+    output << toBinaryString(MSG_TYPE_PERF_TIME);
+    output << toBinaryString(time);
+    output << toBinaryString(timeMax);
+
+    std::string binary = output.str();
+    int size = binary.size();
+
+    if ((writeHelp(&size,
+                   sizeof(int)) == ERROR) ||
+        (writeHelp(binary.c_str(), size) == ERROR))
+    {
+        return ERROR;
+    }
+    return SUCCESS;
+}
+
+PipeWrapper::Status PipeWrapper::receive(int &code,
+                                         int &msgType,
+                                         std::string &data,
+                                         std::chrono::system_clock::duration &time,
+                                         std::chrono::system_clock::duration &timeMax,
+                                         time_t deadline)
 {
     if (m_pipefd[0] == PIPE_CLOSED) {
         return ERROR;
@@ -152,12 +187,24 @@ PipeWrapper::Status PipeWrapper::receive(int &code, std::string &data, time_t de
         queue.AppendCopy(&buffer[0], size);
 
         queue.FlattenConsume(&code, sizeof(int));
-        queue.FlattenConsume(&size, sizeof(int));
-
-        buffer.resize(size);
-
-        queue.FlattenConsume(&buffer[0], size);
-        data.assign(buffer.begin(), buffer.end());
+        queue.FlattenConsume(&msgType, sizeof(int));
+
+        switch (msgType) {
+        case MSG_TYPE_MESSAGE:
+            queue.FlattenConsume(&size, sizeof(int));
+
+            buffer.resize(size);
+
+            queue.FlattenConsume(&buffer[0], size);
+            data.assign(buffer.begin(), buffer.end());
+            break;
+        case MSG_TYPE_PERF_TIME:
+            queue.FlattenConsume(&time, sizeof(std::chrono::system_clock::duration));
+            queue.FlattenConsume(&timeMax, sizeof(std::chrono::system_clock::duration));
+            break;
+        default:
+            return ERROR;
+        }
     } catch (DPL::BinaryQueue::Exception::Base &e) {
         return ERROR;
     }
@@ -177,6 +224,13 @@ std::string PipeWrapper::toBinaryString(int data)
     return std::string(buffer, buffer + sizeof(int));
 }
 
+std::string PipeWrapper::toBinaryString(std::chrono::system_clock::duration data)
+{
+    char buffer[sizeof(std::chrono::system_clock::duration)];
+    memcpy(buffer, &data, sizeof(std::chrono::system_clock::duration));
+    return std::string(buffer, buffer + sizeof(std::chrono::system_clock::duration));
+}
+
 void PipeWrapper::closeHelp(int desc)
 {
     if (m_pipefd[desc] != PIPE_CLOSED) {
@@ -259,9 +313,12 @@ void RunChildProc(TestRunner::TestCase procChild)
         pipe.setUsage(PipeWrapper::READONLY);
 
         int code;
+        int msgType;
+        std::chrono::system_clock::duration time_m;
+        std::chrono::system_clock::duration timeMax_m;
         std::string message;
 
-        int pipeReturn = pipe.receive(code, message, time(0) + 10);
+        int pipeReturn = pipe.receive(code, msgType, message, time_m, timeMax_m, time(0) + 10);
 
         if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error
             pipe.closeAll();
@@ -279,6 +336,12 @@ void RunChildProc(TestRunner::TestCase procChild)
             throw TestRunner::TestFailed("Reading pipe error");
         }
 
+        if (code == CHILD_TEST_PASS && msgType == MSG_TYPE_PERF_TIME) {
+            DPL::Test::TestRunnerSingleton::Instance().setCurrentTestCasePerformanceResult(true,
+                                                                                           time_m,
+                                                                                           timeMax_m);
+        }
+
         if (code == CHILD_TEST_FAIL) {
             throw TestRunner::TestFailed(message);
         } else if (code == CHILD_TEST_IGNORED) {
@@ -292,6 +355,9 @@ void RunChildProc(TestRunner::TestCase procChild)
 
         int code = CHILD_TEST_PASS;
         std::string msg;
+        bool isPerformanceTest;
+        std::chrono::system_clock::duration time_m;
+        std::chrono::system_clock::duration timeMax_m;
 
         bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs();
 
@@ -319,7 +385,17 @@ void RunChildProc(TestRunner::TestCase procChild)
             closeOutput();
         }
 
-        pipe.send(code, msg);
+        DPL::Test::TestRunnerSingleton::Instance().getCurrentTestCasePerformanceResult(isPerformanceTest,
+                                                                                       time_m,
+                                                                                       timeMax_m);
+
+        if (code == CHILD_TEST_PASS && isPerformanceTest){
+            pipe.sendTime(code,
+                    time_m,
+                    timeMax_m);
+        } else {
+            pipe.send(code, msg);
+        }
     }
 }
 } // namespace Test