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 
16 #include <gtest/gtest.h>
17 #include <thread>
18 
19 #include "db_common.h"
20 #include "db_constant.h"
21 #include "db_types.h"
22 #include "distributeddb_data_generate_unit_test.h"
23 #include "ikvdb_raw_cursor.h"
24 #include "kv_store_nb_delegate_impl.h"
25 #include "kvdb_manager.h"
26 #include "platform_specific.h"
27 #include "result_entries_window.h"
28 #include "sqlite_single_ver_forward_cursor.h"
29 #include "sqlite_single_ver_natural_store.h"
30 #include "sqlite_single_ver_natural_store_connection.h"
31 
32 using namespace testing::ext;
33 using namespace DistributedDB;
34 using namespace DistributedDBUnitTest;
35 using namespace std;
36 
37 namespace {
38     string g_testDir;
39     string g_identifier;
40     IKvDBRawCursor *g_rawCursor = nullptr;
41     KvStoreDelegateManager g_mgr(APP_ID, USER_ID);
42     KvStoreConfig g_config;
43     KvStoreNbDelegate *g_kvNbDelegatePtr = nullptr;
44     DBStatus g_kvDelegateStatus = INVALID_ARGS;
45     SQLiteSingleVerNaturalStore *g_store = nullptr;
46     DistributedDB::SQLiteSingleVerNaturalStoreConnection *g_connection = nullptr;
47     const string STORE_ID = STORE_ID_SYNC;
48     auto g_kvNbDelegateCallback = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback,
49         placeholders::_1, placeholders::_2, std::ref(g_kvDelegateStatus), std::ref(g_kvNbDelegatePtr));
50     const int TIME_LAG = 100;
51     const int INITIAL_POSITION = 0;
52     const int SECOND_POSITION = 1;
53     const int TOTAL_COUNT = 3;
54     const Key KEY_PREFIX = {'K'};
55     const Key LOCAL_KEY_1 = {'K', '1'};
56     const Key LOCAL_KEY_2 = {'K', '2'};
57     const Key LOCAL_KEY_3 = {'K', '3'};
58     const Key LOCAL_KEY_4 = {'K', '4'};
59 }
60 
61 class DistributedDBInterfacesSingleVersionResultSetTest : public testing::Test {
62 public:
63     static void SetUpTestCase(void);
64     static void TearDownTestCase(void);
65     void SetUp();
66     void TearDown();
67 };
68 
SetUpTestCase(void)69 void DistributedDBInterfacesSingleVersionResultSetTest::SetUpTestCase(void)
70 {
71     DistributedDBToolsUnitTest::TestDirInit(g_testDir);
72     g_config.dataDir = g_testDir;
73     g_mgr.SetKvStoreConfig(g_config);
74     std::string origIdentifier = USER_ID + "-" + APP_ID + "-" + STORE_ID;
75     std::string identifier = DBCommon::TransferHashString(origIdentifier);
76     g_identifier = DBCommon::TransferStringToHex(identifier);
77     string dir = g_testDir + g_identifier + "/" + DBConstant::SINGLE_SUB_DIR;
78     DIR *dirTmp = opendir(dir.c_str());
79     if (dirTmp == nullptr) {
80         OS::MakeDBDirectory(dir);
81     } else {
82         closedir(dirTmp);
83     }
84 }
85 
TearDownTestCase(void)86 void DistributedDBInterfacesSingleVersionResultSetTest::TearDownTestCase(void)
87 {
88     if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir + STORE_ID + "/" + DBConstant::SINGLE_SUB_DIR) != 0) {
89         LOGE("rm test db files error!");
90     }
91 
92     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_LAG));
93 }
94 
SetUp(void)95 void DistributedDBInterfacesSingleVersionResultSetTest::SetUp(void)
96 {
97     DistributedDBToolsUnitTest::PrintTestCaseInfo();
98     KvStoreNbDelegate::Option delegateOption = {true};
99     g_mgr.GetKvStore(STORE_ID, delegateOption, g_kvNbDelegateCallback);
100     EXPECT_TRUE(g_kvDelegateStatus == OK);
101     ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
102 
103     KvDBProperties property;
104     property.SetStringProp(KvDBProperties::DATA_DIR, g_testDir);
105     property.SetStringProp(KvDBProperties::STORE_ID, STORE_ID);
106     property.SetStringProp(KvDBProperties::IDENTIFIER_DIR, g_identifier);
107     property.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::SINGLE_VER_TYPE_SQLITE);
108 
109     g_store = new (std::nothrow) SQLiteSingleVerNaturalStore;
110     ASSERT_NE(g_store, nullptr);
111     ASSERT_EQ(g_store->Open(property), E_OK);
112 
113     int errCode = E_OK;
114     g_connection = static_cast<SQLiteSingleVerNaturalStoreConnection *>(g_store->GetDBConnection(errCode));
115     ASSERT_NE(g_connection, nullptr);
116     g_store->DecObjRef(g_store);
117     EXPECT_EQ(errCode, E_OK);
118 
119     /**
120      * @tc.steps:step1. Put 3 data items.
121      * @tc.expected: step1.
122      */
123     IOption option;
124     option.dataType = IOption::SYNC_DATA;
125     g_connection->Clear(option);
126     ASSERT_EQ(g_connection->Put(option, LOCAL_KEY_1, VALUE_1), E_OK);
127     ASSERT_EQ(g_connection->Put(option, LOCAL_KEY_2, VALUE_2), E_OK);
128     ASSERT_EQ(g_connection->Put(option, LOCAL_KEY_3, VALUE_3), E_OK);
129 
130     EXPECT_EQ(errCode, E_OK);
131     g_rawCursor = new (std::nothrow) SQLiteSingleVerForwardCursor(g_store, KEY_PREFIX);
132     ASSERT_NE(g_rawCursor, nullptr);
133 }
134 
TearDown(void)135 void DistributedDBInterfacesSingleVersionResultSetTest::TearDown(void)
136 {
137     if (g_connection != nullptr) {
138         g_connection->Close();
139         g_connection = nullptr;
140     }
141 
142     g_store = nullptr;
143 
144     if (g_kvNbDelegatePtr != nullptr) {
145         EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
146         g_kvNbDelegatePtr = nullptr;
147         EXPECT_TRUE(g_mgr.DeleteKvStore(STORE_ID) == OK);
148     }
149 
150     if (g_rawCursor != nullptr) {
151         delete g_rawCursor;
152         g_rawCursor = nullptr;
153     }
154 
155     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_LAG));
156 }
157 
158 /**
159   * @tc.name: SingleVersionResultSetTest001
160   * @tc.desc: CursorWindow Class: Return error when the window size too large.
161   * @tc.type: FUNC
162   * @tc.require: AR000D08KT
163   * @tc.author: maokeheng
164   */
165 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest001, TestSize.Level1)
166 {
167     /**
168      * @tc.steps:step1. Let the WindowSize be INT_MAX, which is larger than the upper limit.
169      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
170      */
171     ResultEntriesWindow resultWindow;
172     double scale = 1;
173     int64_t windoweSize = 0x100000000L; // 4G
174     EXPECT_EQ(resultWindow.Init(g_rawCursor, windoweSize, scale), -E_INVALID_ARGS);
175 }
176 
177 /**
178   * @tc.name: SingleVersionResultSetTest002
179   * @tc.desc: CursorWindow Class: Return error when the window size is negative.
180   * @tc.type: FUNC
181   * @tc.require: AR000D08KT
182   * @tc.author: maokeheng
183   */
184 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest002, TestSize.Level1)
185 {
186     /**
187      * @tc.steps:step1. Let the WindowSize be -1.
188      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
189      */
190     ResultEntriesWindow resultWindow;
191     double scale = 1;
192     int windowSize = -1;
193     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), -E_INVALID_ARGS);
194 }
195 
196 /**
197   * @tc.name: SingleVersionResultSetTest003
198   * @tc.desc: CursorWindow Class: Return error when the window size is zero.
199   * @tc.type: FUNC
200   * @tc.require: AR000D08KT
201   * @tc.author: maokeheng
202   */
203 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest003, TestSize.Level1)
204 {
205     /**
206      * @tc.steps:step1. Let the WindowSize be 0.
207      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
208      */
209     ResultEntriesWindow resultWindow;
210     double scale = 1;
211     int windowSize = 0;
212     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), -E_INVALID_ARGS);
213 }
214 
215 /**
216   * @tc.name: SingleVersionResultSetTest004
217   * @tc.desc: CursorWindow Class: Return OK when the window size is positive.
218   * @tc.type: FUNC
219   * @tc.require: AR000D08KT
220   * @tc.author: maokeheng
221   */
222 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest004, TestSize.Level1)
223 {
224     /**
225      * @tc.steps:step1. Let the WindowSize be 100, which is smaller than the upper limit.
226      * @tc.expected: step1. Expect return OK.
227      */
228     ResultEntriesWindow resultWindow;
229     double scale = 1;
230     int windowSize = 100;
231     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
232 }
233 
234 /**
235   * @tc.name: SingleVersionResultSetTest005
236   * @tc.desc: CursorWindow Class: Return -E_INVALID_ARGS when the window scale is negative.
237   * @tc.type: FUNC
238   * @tc.require: AR000D08KT
239   * @tc.author: maokeheng
240   */
241 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest005, TestSize.Level1)
242 {
243     /**
244      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be negative (-1).
245      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
246      */
247     ResultEntriesWindow resultWindow;
248     double scale = -1;
249     int windowSize = 100;
250     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), -E_INVALID_ARGS);
251 }
252 
253 /**
254   * @tc.name: SingleVersionResultSetTest006
255   * @tc.desc: CursorWindow Class: Return -E_INVALID_ARGS when the window scale is larger than 1.
256   * @tc.type: FUNC
257   * @tc.require: AR000D08KT
258   * @tc.author: maokeheng
259   */
260 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest006, TestSize.Level1)
261 {
262     /**
263      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 2.
264      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
265      */
266     ResultEntriesWindow resultWindow;
267     double scale = 2;
268     int windowSize = 100;
269     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), -E_INVALID_ARGS);
270 }
271 
272 /**
273   * @tc.name: SingleVersionResultSetTest007
274   * @tc.desc: CursorWindow Class: Return -E_INVALID_ARGS when the window scale 0.
275   * @tc.type: FUNC
276   * @tc.require: AR000D08KT
277   * @tc.author: maokeheng
278   */
279 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest007, TestSize.Level1)
280 {
281     /**
282      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 0.
283      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
284      */
285     ResultEntriesWindow resultWindow;
286     double scale = 0;
287     int windowSize = 100;
288     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), -E_INVALID_ARGS);
289 }
290 
291 /**
292   * @tc.name: SingleVersionResultSetTest008
293   * @tc.desc: CursorWindow Class: Return OK when the window scale is between 0 and 1.
294   * @tc.type: FUNC
295   * @tc.require: AR000D08KT
296   * @tc.author: maokeheng
297   */
298 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest008, TestSize.Level1)
299 {
300     /**
301      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 0.5.
302      * @tc.expected: step1. Expect return OK.
303      */
304     ResultEntriesWindow resultWindow;
305     double scale = 0.5;
306     int windowSize = 100;
307     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
308 }
309 
310 /**
311   * @tc.name: SingleVersionResultSetTest009
312   * @tc.desc: CursorWindow Class: Return -E_INVALID_ARGS when the g_rawCursor is nulSSSlptr.
313   * @tc.type: FUNC
314   * @tc.require: AR000D08KT
315   * @tc.author: maokeheng
316   */
317 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest009, TestSize.Level1)
318 {
319     /**
320      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
321      * @tc.expected: step1. Expect return -E_INVALID_ARGS.
322      */
323     IKvDBRawCursor *rawCursor = nullptr;
324     ResultEntriesWindow resultWindow;
325     double scale = 1;
326     int windowSize = 100;
327     EXPECT_EQ(resultWindow.Init(rawCursor, windowSize, scale), -E_INVALID_ARGS);
328 }
329 
330 /**
331   * @tc.name: SingleVersionResultSetTest010
332   * @tc.desc: CursorWindow Class: Check if get total count is feasible.
333   * @tc.type: FUNC
334   * @tc.require: AR000D08KT
335   * @tc.author: maokeheng
336   */
337 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest010, TestSize.Level1)
338 {
339     /**
340      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
341      * @tc.expected: step1. Expect return OK.
342      */
343     ResultEntriesWindow resultWindow;
344     double scale = 1;
345     int windowSize = 100;
346     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
347 
348     /**
349      * @tc.steps:step2. Get the total count.
350      * @tc.expected: step2. Expect return 3.
351      */
352     EXPECT_EQ(resultWindow.GetTotalCount(), TOTAL_COUNT);
353 }
354 
355 /**
356   * @tc.name: SingleVersionResultSetTest011
357   * @tc.desc: CursorWindow Class: Check if get total count is feasible and the inserted items after
358   *           creating ResultEntriesWindow have not been counted.
359   * @tc.type: FUNC
360   * @tc.require: AR000D08KT
361   * @tc.author: maokeheng
362   */
363 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest011, TestSize.Level1)
364 {
365     /**
366      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
367      * @tc.expected: step1. Expect return OK.
368      */
369     ResultEntriesWindow resultWindow;
370     double scale = 1;
371     int windowSize = 100;
372     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
373 
374     /**
375      * @tc.steps:step2. Get the total count.
376      * @tc.expected: step2. Expect return 3.
377      */
378     EXPECT_EQ(resultWindow.GetTotalCount(), TOTAL_COUNT);
379 
380     /**
381      * @tc.steps:step3. Put one more item
382      * @tc.expected: step3.
383      */
384     IOption option;
385     option.dataType = IOption::SYNC_DATA;
386     ASSERT_EQ(g_connection->Put(option, LOCAL_KEY_4, VALUE_4), E_OK);
387 
388     /**
389      * @tc.steps:step4. Get the total count.
390      * @tc.expected: step4. Expect return 3.
391      */
392     EXPECT_EQ(resultWindow.GetTotalCount(), TOTAL_COUNT);
393 }
394 
395 /**
396   * @tc.name: SingleVersionResultSetTest012
397   * @tc.desc: CursorWindow Class: Check if current position after initialization is at 0.
398   * @tc.type: FUNC
399   * @tc.require: AR000D08KT
400   * @tc.author: maokeheng
401   */
402 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest012, TestSize.Level1)
403 {
404     /**
405      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
406      * @tc.expected: step1. Expect return OK.
407      */
408     ResultEntriesWindow resultWindow;
409     double scale = 1;
410     int windowSize = 100;
411     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
412 
413     /**
414      * @tc.steps:step2. Get initial position.
415      * @tc.expected: step2. Expect return INITIAL_POSITION (which is 0).
416      */
417     EXPECT_EQ(resultWindow.GetCurrentPosition(), INITIAL_POSITION);
418 
419     /**
420      * @tc.steps:step3. Get entry .
421      * @tc.expected: step3. Expect return E_OK.
422      */
423     Entry entry;
424     EXPECT_EQ(resultWindow.GetEntry(entry), E_OK);
425     EXPECT_EQ(entry.key, LOCAL_KEY_1);
426     EXPECT_EQ(entry.value, VALUE_1);
427 }
428 
429 /**
430   * @tc.name: SingleVersionResultSetTest013
431   * @tc.desc: CursorWindow Class: Check if current position after move is at the right place+.
432   * @tc.type: FUNC
433   * @tc.require: AR000D08KT
434   * @tc.author: maokeheng
435   */
436 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest013, TestSize.Level1)
437 {
438     /**
439      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
440      * @tc.expected: step1. Expect return OK.
441      */
442     ResultEntriesWindow resultWindow;
443     double scale = 1;
444     int windowSize = 100;
445     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
446 
447     /**
448      * @tc.steps:step2. move to second position.
449      * @tc.expected: step2. Expect return SECOND_POSITION (which is 2).
450      */
451     EXPECT_EQ(resultWindow.MoveToPosition(SECOND_POSITION), true);
452     EXPECT_EQ(resultWindow.GetCurrentPosition(), SECOND_POSITION);
453 
454     /**
455      * @tc.steps:step3. Get entry .
456      * @tc.expected: step3. Expect return OK and entry corresponds to the right item.
457      */
458     Entry entry;
459     EXPECT_EQ(resultWindow.GetEntry(entry), E_OK);
460     EXPECT_EQ(entry.key, LOCAL_KEY_2);
461     EXPECT_EQ(entry.value, VALUE_2);
462 }
463 
464 /**
465   * @tc.name: SingleVersionResultSetTest014
466   * @tc.desc: CursorWindow Class: Move to negative position and the position bounces back to zero.
467   * @tc.type: FUNC
468   * @tc.require: AR000D08KT
469   * @tc.author: maokeheng
470   */
471 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest014, TestSize.Level1)
472 {
473     /**
474      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
475      * @tc.expected: step1. Expect return OK.
476      */
477     ResultEntriesWindow resultWindow;
478     double scale = 1;
479     int windowSize = 100;
480     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
481 
482     /**
483      * @tc.steps:step2. move to second position.
484      * @tc.expected: step2. Expect return false and initial position.
485      */
486     int negativePosition = -2;
487     EXPECT_EQ(resultWindow.MoveToPosition(negativePosition), false);
488     EXPECT_EQ(resultWindow.GetCurrentPosition(), INITIAL_POSITION);
489 
490     /**
491      * @tc.steps:step3. Get entry .
492      * @tc.expected: step3. Expect return E_OK.
493      */
494     Entry entry;
495     EXPECT_EQ(resultWindow.GetEntry(entry), E_OK);
496     EXPECT_EQ(entry.key, LOCAL_KEY_1);
497     EXPECT_EQ(entry.value, VALUE_1);
498 }
499 
500 /**
501   * @tc.name: SingleVersionResultSetTest015
502   * @tc.desc: CursorWindow Class: Move to position larger than N and the position bounces back to original position.
503   * @tc.type: FUNC
504   * @tc.require: AR000D08KT
505   * @tc.author: maokeheng
506   */
507 HWTEST_F(DistributedDBInterfacesSingleVersionResultSetTest, SingleVersionResultSetTest015, TestSize.Level1)
508 {
509     /**
510      * @tc.steps:step1. Let the WindowSize be 100, and window scale to be 1 and resultWindow be null pointer.
511      * @tc.expected: step1. Expect return OK.
512      */
513     ResultEntriesWindow resultWindow;
514     double scale = 1;
515     int windowSize = 100;
516     EXPECT_EQ(resultWindow.Init(g_rawCursor, windowSize, scale), E_OK);
517 
518     /**
519      * @tc.steps:step2. move to second position.
520      * @tc.expected: step2. Expect return false and move to total count.
521      */
522     int largePosition = TOTAL_COUNT + 1;
523     EXPECT_EQ(resultWindow.MoveToPosition(largePosition), false);
524     EXPECT_EQ(resultWindow.GetCurrentPosition(), INITIAL_POSITION);
525 
526     /**
527      * @tc.steps:step3. Get entry .
528      * @tc.expected: step3. Expect return VALUE_1.
529      */
530     Entry entry;
531     EXPECT_EQ(resultWindow.GetEntry(entry), E_OK);
532     EXPECT_EQ(entry.key, LOCAL_KEY_1);
533     EXPECT_EQ(entry.value, VALUE_1);
534 }