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_map.h"
16 
17 #include <array>
18 #include <future>
19 #include <gtest/gtest.h>
20 #include <iostream>
21 #include <thread>
22 #include <chrono> // std::chrono::seconds
23 using namespace testing::ext;
24 using namespace std;
25 
26 namespace OHOS {
27 namespace {
28 class UtilsSafeMap : public testing::Test {
29 };
30 
31 /*
32  * @tc.name: testUtilsCopyAndAssign001
33  * @tc.desc: single thread test the normal feature insert and erase and EnsureInsert
34  */
35 HWTEST_F(UtilsSafeMap, testUtilsCopyAndAssign001, TestSize.Level0)
36 {
37     SafeMap<string, int> demoData;
38     // insert new
39     demoData.Insert("A", 1);
40     ASSERT_FALSE(demoData.IsEmpty());
41     ASSERT_EQ(demoData.Size(), 1);
42 
43     SafeMap<string, int> newdemo = demoData;
44     int tar = -1;
45     ASSERT_TRUE(newdemo.Find("A", tar));
46     ASSERT_EQ(1, tar);
47 
48     tar = -1;
49     SafeMap<string, int> newdemo2;
50     newdemo2 = demoData;
51     ASSERT_TRUE(newdemo2.Find("A", tar));
52     ASSERT_EQ(1, tar);
53 }
54 
55 /*
56  * @tc.name: testUtilsoperator001
57  * @tc.desc: SafeMap
58  */
59 HWTEST_F(UtilsSafeMap, testUtilsoperator001, TestSize.Level0)
60 {
61     SafeMap<string, int> demoData;
62     // insert new
63     demoData.Insert("A", 1);
64     ASSERT_FALSE(demoData.IsEmpty());
65     ASSERT_EQ(demoData.Size(), 1);
66     ASSERT_EQ(demoData.ReadVal("A"), 1);
67 
68     SafeMap<string, int> newdemo = demoData;
69     ASSERT_EQ(newdemo.ReadVal("A"), 1);
70 
71     int tar = -1;
72     newdemo.Insert("B", 6);
73     ASSERT_TRUE(newdemo.Find("B", tar));
74     ASSERT_EQ(6, tar);
75 
76     SafeMap<string, int> newdemo2;
77     newdemo2 = newdemo;
78     ASSERT_EQ(newdemo2.ReadVal("A"), 1);
79 }
80 
81 /*
82  * @tc.name: testUtilsNormalFeatureInsert001
83  * @tc.desc: SafeMap
84  */
85 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureInsert001, TestSize.Level0)
86 {
87     SafeMap<string, int> demoData;
88     ASSERT_TRUE(demoData.IsEmpty());
89     // insert new
90     demoData.Insert("A", 1);
91     ASSERT_FALSE(demoData.IsEmpty());
92     ASSERT_EQ(demoData.Size(), 1);
93 
94     // insert copy one should fail
95     ASSERT_FALSE(demoData.Insert("A", 2));
96     ASSERT_EQ(demoData.Size(), 1);
97 }
98 
99 /*
100  * @tc.name: testUtilsNormalFeatureEnsureInsert001
101  * @tc.desc: SafeMap
102  */
103 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureEnsureInsert001, TestSize.Level0)
104 {
105     SafeMap<string, int> demoData;
106     ASSERT_TRUE(demoData.IsEmpty());
107 
108     demoData.Insert("A", 1);
109     demoData.EnsureInsert("B", 2);
110 
111     ASSERT_FALSE(demoData.IsEmpty());
112     ASSERT_EQ(demoData.Size(), 2);
113     // insert copy one and new one
114     demoData.EnsureInsert("B", 5);
115     demoData.EnsureInsert("C", 6);
116 
117     ASSERT_EQ(demoData.Size(), 3);
118 }
119 
120 /*
121  * @tc.name: testUtilsNormalFeatureFind001
122  * @tc.desc: SafeMap
123  */
124 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureFind001, TestSize.Level0)
125 {
126     SafeMap<string, int> demoData;
127     ASSERT_TRUE(demoData.IsEmpty());
128 
129     demoData.Insert("A", 1);
130     demoData.Insert("B", 10000);
131     demoData.EnsureInsert("B", 2);
132     demoData.EnsureInsert("C", 6);
133 
134     ASSERT_FALSE(demoData.IsEmpty());
135     ASSERT_EQ(demoData.Size(), 3);
136 
137     int i = 0;
138     ASSERT_TRUE(demoData.Find("A", i));
139     ASSERT_EQ(i, 1);
140     ASSERT_TRUE(demoData.Find("B", i));
141     ASSERT_EQ(i, 2);
142 
143     ASSERT_TRUE(demoData.Find("C", i));
144     ASSERT_EQ(i, 6);
145 }
146 
147 /*
148  * @tc.name: testUtilsNormalFeatureFindAndSet001
149  * @tc.desc: SafeMap
150  */
151 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureFindAndSet001, TestSize.Level0)
152 {
153     SafeMap<string, int> demoData;
154     ASSERT_TRUE(demoData.IsEmpty());
155 
156     demoData.Insert("A", 1);
157     demoData.EnsureInsert("B", 2);
158 
159     int oldvalue = 0;
160     int newvalue = 3;
161     ASSERT_TRUE(demoData.FindOldAndSetNew("A", oldvalue, newvalue));
162     // old value
163     ASSERT_EQ(oldvalue, 1);
164 
165     newvalue = 4;
166     ASSERT_TRUE(demoData.FindOldAndSetNew("B", oldvalue, newvalue));
167     // old value
168     ASSERT_EQ(oldvalue, 2);
169     int i = -1;
170     ASSERT_TRUE(demoData.Find("A", i));
171     // new value
172     ASSERT_EQ(i, 3);
173     ASSERT_TRUE(demoData.Find("B", i));
174     // new value
175     ASSERT_EQ(i, 4);
176 }
177 
178 /*
179  * @tc.name: testUtilsNormalFeatureEraseAndClear001
180  * @tc.desc: SafeMap
181  */
182 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureEraseAndClear001, TestSize.Level0)
183 {
184     SafeMap<string, int> demoData;
185     ASSERT_TRUE(demoData.IsEmpty());
186 
187     demoData.Insert("A", 1);
188     demoData.EnsureInsert("B", 2);
189 
190     ASSERT_EQ(demoData.Size(), 2);
191     demoData.Erase("A");
192     ASSERT_EQ(demoData.Size(), 1);
193 
194     demoData.Clear();
195     ASSERT_EQ(demoData.Size(), 0);
196 }
197 
198 /*
199  * @tc.name: testUtilsNormalFeatureIterate001
200  * @tc.desc: Using Iterate to change the second parameter of SafeMap
201  */
Callback(const std::string str,int & value)202 void Callback(const std::string str, int& value)
203 {
204     value++;
205 }
206 
207 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureIterate001, TestSize.Level0)
208 {
209     SafeMap<string, int> demoData;
210     ASSERT_TRUE(demoData.IsEmpty());
211 
212     demoData.Insert("A", 1);
213     demoData.Insert("B", 2);
214     demoData.Insert("C", 3);
215     demoData.Insert("D", 4);
216     demoData.Iterate(Callback);
217 
218     ASSERT_EQ(demoData.Size(), 4);
219     ASSERT_EQ(demoData.ReadVal("A"), 2);
220     ASSERT_EQ(demoData.ReadVal("B"), 3);
221     ASSERT_EQ(demoData.ReadVal("C"), 4);
222     ASSERT_EQ(demoData.ReadVal("D"), 5);
223 }
224 
225 /*
226  * @tc.name: testUtilsConcurrentIterate001
227  * @tc.desc: 100 threads test in iterate operation to rewrite a SafeMap.
228  */
229 const int THREAD_NUM = 100;
230 const int DATA_NUM = 10;
231 HWTEST_F(UtilsSafeMap, testUtilsConcurrentIterate001, TestSize.Level0)
232 {
233     SafeMap<string, int> demoData;
234     for (int i = 0; i < DATA_NUM; i++) {
235         demoData.Insert("A" + std::to_string(i), 0);
236     }
237     std::thread threads[THREAD_NUM];
238 
239     ASSERT_NO_THROW({
240         auto lamfuncIterate = [](SafeMap<string, int>& data, const int& cnt,
__anonf4da918c0202(SafeMap<string, int>& data, const int& cnt, const std::chrono::system_clock::time_point& absTime) 241             const std::chrono::system_clock::time_point& absTime) {
242             auto callback_it = [cnt](const string data, int& value) {
243                 value = cnt;
244             };
245             std::this_thread::sleep_until(absTime);
246             data.Iterate(callback_it);
247         };
248 
249         using std::chrono::system_clock;
250 
251         std::time_t timeT = system_clock::to_time_t(system_clock::now());
252         timeT += 2;
253 
254         for (int i = 0; i < THREAD_NUM; ++i) {
255             threads[i] = std::thread(lamfuncIterate, std::ref(demoData), i, system_clock::from_time_t(timeT));
256         }
257 
258         std::this_thread::sleep_for(std::chrono::seconds(3));
259         for (auto& t : threads) {
260             t.join();
261         }
262 
263         for (int i = 0; i < DATA_NUM - 1; i++) {
264             ASSERT_EQ(demoData.ReadVal("A" + std::to_string(i)), demoData.ReadVal("A" + std::to_string(i + 1)));
265         }
266     });
267 }
268 
269 /*
270  * @tc.name: testUtilsConcurrentWriteAndRead001
271  * @tc.desc: 100 threads test in writein to the same key of the map, while read at same time  and no throw
272  */
273 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndRead001, TestSize.Level0)
274 {
275     SafeMap<string, int> demoData;
276     std::thread threads[THREAD_NUM];
277     std::thread checkThread[THREAD_NUM];
278     ASSERT_NO_THROW({
279         auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0402(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 280             const int& value, const std::chrono::system_clock::time_point& absTime) {
281             std::this_thread::sleep_until(absTime);
282             data.EnsureInsert(key, value);
283         };
284 
285         auto lamfuncCheck = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0502(SafeMap<string, int>& data, const string& key, std::chrono::system_clock::time_point absTime) 286             std::chrono::system_clock::time_point absTime) {
287             std::this_thread::sleep_until(absTime);
288             thread_local int i = -1;
289             data.Find(key, i);
290         };
291 
292         using std::chrono::system_clock;
293 
294         std::time_t timeT = system_clock::to_time_t(system_clock::now());
295         timeT += 2;
296         string key("A");
297 
298         for (int i = 0; i < THREAD_NUM; ++i) {
299             threads[i] = std::thread(lamfuncInsert, std::ref(demoData), key, i, system_clock::from_time_t(timeT));
300             checkThread[i] = std::thread(lamfuncCheck, std::ref(demoData), key, system_clock::from_time_t(timeT));
301         }
302 
303         std::this_thread::sleep_for(std::chrono::seconds(3));
304         for (auto& t : threads) {
305             t.join();
306         }
307 
308         for (auto& t : checkThread) {
309             t.join();
310         }
311     });
312 }
313 
314 /*
315  * @tc.name: testUtilsConcurrentWriteAndFind001
316  * @tc.desc: 100 threads test in writein to the corresponding key of the map,
317  * while read at same time  and check the results
318  */
319 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndFind001, TestSize.Level0)
320 {
321     SafeMap<string, int> demoData;
322     std::thread threads[THREAD_NUM];
323     std::vector<std::future<int>> vcfi;
324 
325     ASSERT_NO_THROW({
326         auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0602(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 327             const int& value, const std::chrono::system_clock::time_point& absTime) {
328             std::this_thread::sleep_until(absTime);
329             data.EnsureInsert(key, value);
330         };
331 
332         auto lamfuncCheckLoop = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0702(SafeMap<string, int>& data, const string& key, std::chrono::system_clock::time_point absTime) 333             std::chrono::system_clock::time_point absTime) {
334             std::this_thread::sleep_until(absTime);
335             thread_local int i = -1;
336             while (!data.Find(key, i)) {
337                 std::this_thread::sleep_for(std::chrono::microseconds(10));
338             }
339             return i;
340         };
341 
342         using std::chrono::system_clock;
343 
344         std::time_t timeT = system_clock::to_time_t(system_clock::now());
345         timeT += 2;
346         string key("A");
347 
348         for (int i = 0; i < THREAD_NUM; ++i) {
349             threads[i] = std::thread(lamfuncInsert, std::ref(demoData),
350                 key + std::to_string(i), i, system_clock::from_time_t(timeT));
351             vcfi.push_back(std::async(std::launch::async, lamfuncCheckLoop,
352                 std::ref(demoData), key + std::to_string(i), system_clock::from_time_t(timeT)));
353         }
354 
355         std::this_thread::sleep_for(std::chrono::seconds(4));
356         for (auto& t : threads) {
357             t.join();
358         }
359 
360         vector<int> result;
361 
362         for (auto& t : vcfi) {
363             result.push_back(t.get());
364         }
365 
366         std::sort(result.begin(), result.end());
367 
368         for (int i = 0; i < THREAD_NUM; ++i) {
369             ASSERT_EQ(i, result[i]);
370         }
371     });
372 }
373 
ResultCompare(std::vector<std::future<int>> & vcfi,SafeMap<string,int> & demoData)374 static void ResultCompare(std::vector<std::future<int>>& vcfi, SafeMap<string, int>& demoData)
375 {
376     vector<int> result;
377     for (auto& t : vcfi) {
378         result.push_back(t.get());
379     }
380 
381     std::sort(result.begin(), result.end());
382 
383     for (int i = 0; i < THREAD_NUM; ++i) {
384         ASSERT_EQ(i, result[i]);
385     }
386 
387     int t = 0;
388     result.clear();
389     for (int i = 0; i < THREAD_NUM; ++i) {
390         t = -1;
391         ASSERT_TRUE(demoData.Find("A" + std::to_string(i), t));
392         result.push_back(t);
393     }
394 
395     std::sort(result.begin(), result.end());
396 
397     for (int i = 0; i < THREAD_NUM; ++i) {
398         ASSERT_EQ(i + 1, result[i]);
399     }
400 }
401 
402 /*
403  * @tc.name: testUtilsConcurrentWriteAndFindAndSet001
404  * @tc.desc: 100 threads test in writein to the corresponding key of the map,
405  * while findandfix at same time  and check the results
406  */
407 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndFindAndSet001, TestSize.Level0)
408 {
409     SafeMap<string, int> demoData;
410     std::thread threads[THREAD_NUM];
411     std::vector<std::future<int>> vcfi;
412 
413     ASSERT_NO_THROW({
414         auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0802(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 415             const int& value, const std::chrono::system_clock::time_point& absTime) {
416             std::this_thread::sleep_until(absTime);
417             data.EnsureInsert(key, value);
418         };
419 
420         auto lamfuncCheckLoop = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0902(SafeMap<string, int>& data, const string& key, const int& newvalue, std::chrono::system_clock::time_point absTime) 421             const int& newvalue, std::chrono::system_clock::time_point absTime) {
422             std::this_thread::sleep_until(absTime);
423             thread_local int i = -1;
424             while (!data.FindOldAndSetNew(key, i, newvalue)) {
425                 std::this_thread::sleep_for(std::chrono::microseconds(10));
426             }
427             return i;
428         };
429 
430         using std::chrono::system_clock;
431 
432         std::time_t timeT = system_clock::to_time_t(system_clock::now());
433         timeT += 2;
434         string key("A");
435 
436         for (int i = 0; i < THREAD_NUM; ++i) {
437             threads[i] = std::thread(lamfuncInsert, std::ref(demoData),
438                 key + std::to_string(i), i, system_clock::from_time_t(timeT));
439             vcfi.push_back(std::async(std::launch::async, lamfuncCheckLoop,
440                 std::ref(demoData), key + std::to_string(i), i + 1, system_clock::from_time_t(timeT)));
441         }
442 
443         std::this_thread::sleep_for(std::chrono::seconds(4));
444         for (auto& t : threads) {
445             t.join();
446         }
447 
448         ResultCompare(vcfi, demoData);
449     });
450 }
451 }  // namespace
452 }  // namespace OHOS