1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "safe_queue.h"
16
17 #include <array>
18 #include <future>
19 #include <gtest/gtest.h>
20 #include <iostream>
21 #include <thread>
22
23 #include <iostream>
24
25 #include <chrono> // std::chrono::seconds
26 #include <iostream> // std::cout
27 #include <thread> // std::thread, std::this_thread::sleep_for
28
29 using namespace testing::ext;
30 using namespace OHOS;
31 using namespace std;
32
33 class UtilsSafeQueue : public testing::Test
34 {
35 };
36
37 const unsigned int QUEUE_SLOTS = 10;
38 const unsigned int THREAD_NUM = QUEUE_SLOTS + 1;
39
40 class DemoThreadData
41 {
42 public:
DemoThreadData()43 DemoThreadData()
44 {
45 putStatus = false;
46 getStatus = false;
47 }
48 static SafeQueue<int> shareQueue;
49 bool putStatus;
50 bool getStatus;
51
Put(int i)52 void Put(int i)
53 {
54 shareQueue.Push(i);
55 putStatus = true;
56 }
57
Get(int & i)58 void Get(int &i)
59 {
60 shareQueue.Pop(i);
61 getStatus = true;
62 }
63 };
64 SafeQueue<int> DemoThreadData::shareQueue;
65
PutHandleThreadDataTime(DemoThreadData & q,int i,std::chrono::system_clock::time_point absTime)66 void PutHandleThreadDataTime(DemoThreadData &q, int i, std::chrono::system_clock::time_point absTime)
67 {
68 cout << "thread-" << std::this_thread::get_id() << " run time: "
69 << std::chrono::system_clock::to_time_t(absTime) << endl;
70 std::this_thread::sleep_until(absTime);
71
72 q.Put(i);
73 }
74
GetHandleThreadDataTime(DemoThreadData & q,int i,std::chrono::system_clock::time_point absTime)75 void GetHandleThreadDataTime(DemoThreadData &q, int i, std::chrono::system_clock::time_point absTime)
76 {
77 cout << "thread-" << std::this_thread::get_id() << " run time: "
78 << std::chrono::system_clock::to_time_t(absTime) << endl;
79 std::this_thread::sleep_until(absTime);
80 int t = 0;
81 q.Get(t);
82 }
83
84 class TestThreading
85 {
86
87 public:
TestThreading()88 TestThreading()
89 {
90 demoDatas.fill(DemoThreadData());
91 }
92
AllThreadPut(std::time_t & timeT)93 void AllThreadPut(std::time_t &timeT)
94 {
95 using std::chrono::system_clock;
96 for (unsigned int i = 0; i < THREAD_NUM; i++)
97 {
98 threads[i] = std::thread(PutHandleThreadDataTime,
99 std::ref(demoDatas[i]), i, system_clock::from_time_t(timeT));
100 }
101 }
AllThreadGet(std::time_t & timeT)102 void AllThreadGet(std::time_t &timeT)
103 {
104 using std::chrono::system_clock;
105 for (unsigned int i = 0; i < THREAD_NUM; i++)
106 {
107 threads[i] = std::thread(GetHandleThreadDataTime,
108 std::ref(demoDatas[i]), i, system_clock::from_time_t(timeT));
109 }
110 }
111
GetThreadDatePushedStatus(unsigned int & pushedIn,unsigned int & unpushedIn)112 void GetThreadDatePushedStatus(unsigned int &pushedIn, unsigned int &unpushedIn)
113 {
114 pushedIn = 0;
115 unpushedIn = 0;
116 for (auto &t : demoDatas)
117 {
118 if (t.putStatus)
119 pushedIn++;
120 else
121 {
122 unpushedIn++;
123 }
124 }
125 }
126
GetThreadDateGetedStatus(unsigned int & getedOut,unsigned int & ungetedOut)127 void GetThreadDateGetedStatus(unsigned int &getedOut, unsigned int &ungetedOut)
128 {
129 getedOut = 0;
130 ungetedOut = 0;
131 for (auto &t : demoDatas)
132 {
133 if (t.getStatus)
134 getedOut++;
135 else
136 {
137 ungetedOut++;
138 }
139 }
140 }
141
ResetStatus()142 void ResetStatus()
143 {
144 for (auto &t : threads)
145 {
146 t.join();
147 }
148
149 DemoThreadData::shareQueue.Clear();
150 }
151
152 std::thread threads[THREAD_NUM];
153 std::array<DemoThreadData, THREAD_NUM> demoDatas;
154 };
155
156 /*
157 * Feature: SafeBlockQueue
158 * Function:put
159 * SubFunction: NA
160 * FunctionPoints:
161 * EnvConditions: NA
162 * CaseDescription: Multiple threads put , one thread gets, all threads finish running normally
163 */
164
165 HWTEST_F(UtilsSafeQueue, testMutilthreadPutAndOneThreadGetOnemptyQueue, TestSize.Level0)
166 {
167
168 TestThreading testThread;
169 using std::chrono::system_clock;
170
171 std::time_t timeT = system_clock::to_time_t(system_clock::now());
172 timeT += 2;
173 testThread.AllThreadPut(timeT);
174
175 // 1. queue is full and some threads is blocked
176 std::this_thread::sleep_for(std::chrono::seconds(3));
177 ASSERT_TRUE(DemoThreadData::shareQueue.Size() > 0);
178
179 unsigned int pushedIn = 0;
180 unsigned int unpushedIn = 0;
181
182 testThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
183
184 ASSERT_EQ(pushedIn, THREAD_NUM);
185
186 //2. get one out and wait some put in
187 for (unsigned int i = 0; i < THREAD_NUM; i++)
188 {
189 int t = 0;
190 testThread.demoDatas[0].Get(t);
191 }
192
193 std::this_thread::sleep_for(std::chrono::seconds(2));
194 // queue is full and some threads is blocked and is not joined
195 ASSERT_TRUE(DemoThreadData::shareQueue.Size() == 0);
196
197 // here means all thread end ok or if some operation blocked and the testcase blocked
198 testThread.ResetStatus();
199 }
200
201 /*
202 * Feature: SafeBlockQueue
203 * Function:put
204 * SubFunction: NA
205 * FunctionPoints:
206 * EnvConditions: NA
207 * CaseDescription: Multi-threaded put() and Multi-threaded get() on the empty queue. When all threads are waiting to reach a certain
208 * time-point, everyone run concurrently to see the status of the queue and the state of the thread.
209 */
210
211 HWTEST_F(UtilsSafeQueue, testMutilthreadPutAndGetConcurrently, TestSize.Level0)
212 {
213
214 using std::chrono::system_clock;
215
216 std::time_t timeT = system_clock::to_time_t(system_clock::now());
217 timeT += 2;
218
219 TestThreading putInTestThread;
220 putInTestThread.AllThreadPut(timeT);
221
222 TestThreading getOutTestThread;
223 getOutTestThread.AllThreadGet(timeT);
224
225 // 1. queue is full and some threads is blocked
226 std::this_thread::sleep_for(std::chrono::seconds(4));
227
228 unsigned int pushedIn = 0;
229 unsigned int unpushedIn = 0;
230 unsigned int getedOut = 0;
231 unsigned int ungetedOut = 0;
232 putInTestThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
233 getOutTestThread.GetThreadDateGetedStatus(getedOut, ungetedOut);
234 cout << "DemoThreadData::shareQueue.Size() = " << DemoThreadData::shareQueue.Size() << endl;
235 ASSERT_EQ(pushedIn, THREAD_NUM);
236 ASSERT_EQ(getedOut, THREAD_NUM);
237
238 putInTestThread.ResetStatus();
239 getOutTestThread.ResetStatus();
240 }
241
242 /*
243 * Feature: SafeBlockQueue
244 * Function:put
245 * SubFunction: NA
246 * FunctionPoints:
247 * EnvConditions: NA
248 * CaseDescription: Multi-threaded put() and Multi-threaded get() on the not empty queue. When all threads are waiting to reach a certain
249 * time-point, everyone run concurrently to see the status of the queue and the state of the thread.
250 */
251 HWTEST_F(UtilsSafeQueue, testMutilthreadConcurrentGetAndPopInNotEmptyQueue, TestSize.Level0)
252 {
253 //1. prepare
254 using std::chrono::system_clock;
255
256 std::time_t timeT = system_clock::to_time_t(system_clock::now());
257 timeT += 2;
258
259 ASSERT_TRUE(DemoThreadData::shareQueue.Size() == 0);
260 int t = 1;
261 for (unsigned int i = 0; i < THREAD_NUM; i++)
262 {
263 DemoThreadData::shareQueue.Push(t);
264 }
265
266 ASSERT_TRUE(DemoThreadData::shareQueue.Size() == THREAD_NUM);
267
268 //2. start thread put in not full queue
269
270 TestThreading putInTestThread;
271 putInTestThread.AllThreadPut(timeT);
272
273 TestThreading getOutTestThread;
274 getOutTestThread.AllThreadGet(timeT);
275
276 std::this_thread::sleep_for(std::chrono::seconds(3));
277 ASSERT_TRUE(DemoThreadData::shareQueue.Size() == THREAD_NUM);
278
279 unsigned int getedOut = 0;
280 unsigned int ungetedOut = 0;
281 unsigned int pushedIn = 0;
282 unsigned int unpushedIn = 0;
283 getOutTestThread.GetThreadDateGetedStatus(getedOut, ungetedOut);
284 putInTestThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
285
286 ASSERT_EQ(pushedIn, THREAD_NUM);
287 ASSERT_EQ(getedOut, THREAD_NUM);
288
289 // 3. reset status
290 putInTestThread.ResetStatus();
291 getOutTestThread.ResetStatus();
292 }
293