plugins: Relocate tests
[iotivity.git] / plugins / unittests / gtest_helper.h
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #ifndef IOTY_GTEST_HELPER_H
22 #define IOTY_GTEST_HELPER_H
23
24 #include <atomic>
25 #include <chrono>
26 #include <condition_variable>
27 #include <future>
28 #include <mutex>
29 #include <thread>
30
31 namespace iotivity
32 {
33     namespace test
34     {
35         /**
36          * Simple implementation of a deadman's timer that can be used to
37          * terminate a test that hangs.
38          *
39          * Since there is no standard way to terminate an individual thread,
40          * the entire process will be killed once time has been exceeded.
41          *
42          * @note provisions for watchdog thread cleanup are not currently added.
43          * Testing has not yet shown any need for such complexity.
44          */
45         class DeadmanTimer
46         {
47         public:
48
49             /**
50              * Creates an instance of a timer set to kill the running process
51              * after the specified timeout.
52              *
53              * If the destructor is invoked before time is up (aka this instance
54              * goes out of scope) the timeout will not cause the program to be
55              * terminated.
56              *
57              * @param time to wait before assuming the process is hung and must be
58              * killed.
59              * Examples of values that can be passed include
60              * std::chrono::milliseconds(250), std::chrono::seconds(5),
61              * std::chrono::minutes(3).
62              */
63             DeadmanTimer(std::chrono::milliseconds timeout) :
64                 m_ctx(new DeadmanCtx(timeout)),
65                 m_thread()
66                 {
67                     m_thread = std::thread([this](){run(m_ctx);});
68                     {
69                         std::unique_lock<std::mutex> lock(m_ctx->m_mutex);
70                         while (!m_ctx->m_isArmed)
71                         {
72                             m_ctx->m_cond.wait(lock);
73                         }
74                     }
75                     // Now that the thread is live, we can stop tracking it.
76                     m_thread.detach();
77                 }
78
79             /**
80              * Destructor that also will cancel the termination of the
81              * running process.
82              */
83             ~DeadmanTimer()
84             {
85                 std::unique_lock<std::mutex> lock(m_ctx->m_mutex);
86                 m_ctx->m_isArmed = false;
87             }
88
89         private:
90
91             /**
92              * Shared data that main and child thread might both need to
93              * access.
94              *
95              * Avoids referencing data in class instances that have been
96              * deleted.
97              */
98             class DeadmanCtx
99             {
100             public:
101
102                 DeadmanCtx(std::chrono::milliseconds timeout) :
103                     m_mutex(),
104                     m_cond(),
105                     m_isArmed(false),
106                     m_timeout(timeout)
107                     {
108                     }
109
110                 std::mutex m_mutex;
111                 std::condition_variable m_cond;
112                 bool m_isArmed;
113                 std::chrono::milliseconds m_timeout;
114             };
115
116             // Explicitly block assignment and copy ctor
117             DeadmanTimer &operator=(const DeadmanTimer &rhs);
118             DeadmanTimer(const iotivity::test::DeadmanTimer &rhs);
119
120             std::shared_ptr<DeadmanCtx> m_ctx;
121             std::thread m_thread;
122
123
124             static void run(std::shared_ptr<DeadmanCtx> ctx)
125             {
126                 // Let the calling thread know it can stop waiting:
127                 {
128                     std::unique_lock<std::mutex> lock(ctx->m_mutex);
129                     ctx->m_isArmed = true;
130                     ctx->m_cond.notify_all();
131                 }
132
133                 std::this_thread::sleep_for(ctx->m_timeout);
134
135                 std::unique_lock<std::mutex> lock(ctx->m_mutex);
136                 if (ctx->m_isArmed)
137                 {
138                     try {
139                         throw std::runtime_error("deadman timer expired");
140                     }
141                     catch (std::exception&)
142                     {
143                         std::terminate();
144                     }
145                 }
146             }
147         };
148     } // namespace test
149 } // namespace iotivity
150
151 #endif // IOTY_GTEST_HELPER_H