• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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