1 /*
2  * Copyright (c) 2023 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 <gtest/gtest.h>
16 #include "distributeddb_tools_unit_test.h"
17 #include "strategy_factory.h"
18 #include "virtual_cloud_syncer.h"
19 
20 using namespace std;
21 using namespace testing::ext;
22 using namespace DistributedDB;
23 
24 namespace {
25 class DistributedDBCloudStrategyTest : public testing::Test {
26 public:
27     static void SetUpTestCase(void);
28     static void TearDownTestCase(void);
29     void SetUp();
30     void TearDown();
31 };
32 
SetUpTestCase(void)33 void DistributedDBCloudStrategyTest::SetUpTestCase(void)
34 {
35 }
36 
TearDownTestCase(void)37 void DistributedDBCloudStrategyTest::TearDownTestCase(void)
38 {
39 }
40 
SetUp(void)41 void DistributedDBCloudStrategyTest::SetUp(void)
42 {
43     DistributedDBUnitTest::DistributedDBToolsUnitTest::PrintTestCaseInfo();
44 }
45 
TearDown(void)46 void DistributedDBCloudStrategyTest::TearDown(void)
47 {
48 }
49 
50 /**
51  * @tc.name: StrategyFactoryTest001
52  * @tc.desc: Verify cloud strategy build function.
53  * @tc.type: FUNC
54  * @tc.require:
55  * @tc.author: zhangqiquan
56  */
57 HWTEST_F(DistributedDBCloudStrategyTest, StrategyFactoryTest001, TestSize.Level0)
58 {
59     /**
60      * @tc.steps: step1. PUSH PULL PUSH_PULL mode will get base strategy
61      * @tc.expected: step1. both judge update cursor and upload got false
62      */
63     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_PUSH_ONLY);
64     ASSERT_NE(strategy, nullptr);
65     EXPECT_EQ(strategy->JudgeUpdateCursor(), false);
66     EXPECT_EQ(strategy->JudgeUpload(), false);
67 
68     strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_PULL_ONLY);
69     ASSERT_NE(strategy, nullptr);
70     EXPECT_EQ(strategy->JudgeUpdateCursor(), false);
71     EXPECT_EQ(strategy->JudgeUpload(), false);
72 
73     strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_PUSH_PULL);
74     ASSERT_NE(strategy, nullptr);
75     EXPECT_EQ(strategy->JudgeUpdateCursor(), false);
76     EXPECT_EQ(strategy->JudgeUpload(), false);
77     /**
78      * @tc.steps: step2. CLOUD_MERGE mode will get cloud merge strategy
79      * @tc.expected: step2. both judge update cursor and upload got true
80      */
81     strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_MERGE);
82     ASSERT_NE(strategy, nullptr);
83     EXPECT_EQ(strategy->JudgeUpdateCursor(), true);
84     EXPECT_EQ(strategy->JudgeUpload(), true);
85 }
86 
87 /**
88  * @tc.name: TagOpTyeTest001
89  * @tc.desc: Verify cloud merge strategy tag operation type function.
90  * @tc.type: FUNC
91  * @tc.require:
92  * @tc.author: zhangqiquan
93  */
94 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest001, TestSize.Level0)
95 {
96     /**
97      * @tc.steps: step1. build cloud merge strategy
98      */
99     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_MERGE);
100     ASSERT_NE(strategy, nullptr);
101     LogInfo localInfo;
102     LogInfo cloudInfo;
103     /**
104      * @tc.steps: step2. local not exist cloud record
105      * @tc.expected: step2. insert cloud record to local
106      */
107     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::INSERT);
108     /**
109      * @tc.steps: step3. local record is newer and local not exist gid, while local data is not sync-ed
110      * @tc.expected: step3. only update gid
111      */
112     localInfo.timestamp = 1u;
113     localInfo.flag = static_cast<uint64_t>(LogInfoFlag::FLAG_LOCAL);
114     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::ONLY_UPDATE_GID);
115     /**
116      * @tc.steps: step4. local record is newer and local exist gid
117      * @tc.expected: step4. no need handle this record
118      */
119     localInfo.cloudGid = "gid";
120     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
121     /**
122      * @tc.steps: step5. cloud record is newer
123      * @tc.expected: step5. update cloud record
124      */
125     cloudInfo.timestamp = 2u; // mark 2 means cloud is new
126     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
127     /**
128      * @tc.steps: step6. cloud record is newer and it is delete
129      * @tc.expected: step6. delete cloud record
130      */
131     cloudInfo.flag = 0x01; // it means delete
132     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::DELETE);
133     /**
134      * @tc.steps: step7. cloud is new and local is delete
135      * @tc.expected: step7 insert cloud record
136      */
137     cloudInfo.flag = 0; // it means no delete
138     localInfo.flag = 0x01; // it means delete
139     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::INSERT);
140     /**
141      * @tc.steps: step8. cloud is new and local both delete
142      * @tc.expected: step8 not handle cloud record
143      */
144     cloudInfo.flag = 0x01; // it means delete
145     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE_TIMESTAMP);
146     /**
147      * @tc.steps: step9. cloud is delete and local not exist
148      * @tc.expected: step9 not handle cloud record
149      */
150     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
151     /**
152      * @tc.steps: step10. cloud is old and delete, local has gid
153      * @tc.expected: step10 clear gid
154      */
155     localInfo.timestamp = 3u; // mark 3 means local is new
156     localInfo.flag = static_cast<uint64_t>(LogInfoFlag::FLAG_LOCAL);
157     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::CLEAR_GID);
158     /**
159      * @tc.steps: step10. cloud is old and delete, local has not gid
160      * @tc.expected: step10 not handle cloud record
161      */
162     localInfo.cloudGid = "";
163     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
164     /**
165      * @tc.steps: step11. cloud has same timestamp with local, and local has empty gid
166      * @tc.expected: step11 only update gid
167      */
168     cloudInfo.timestamp = localInfo.timestamp;
169     cloudInfo.flag = 0; // it means no delete
170     localInfo.flag = 0; // it means no delete
171     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::ONLY_UPDATE_GID);
172 
173     /**
174      * @tc.steps: step12. local record is newer and local not exist gid, while record is sync-ed
175      * @tc.expected: step12. update
176      */
177     localInfo.timestamp = 4u;
178     localInfo.flag = static_cast<uint64_t>(LogInfoFlag::FLAG_CLOUD);
179     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
180 }
181 
182 /**
183  * @tc.name: TagOpTyeTest002
184  * @tc.desc: Verify local cover cloud strategy tag operation type function.
185  * @tc.type: FUNC
186  * @tc.require:
187  * @tc.author: huangboxin
188  */
189 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest002, TestSize.Level0)
190 {
191     /**
192      * @tc.steps: step1. build local cover cloud strategy
193      */
194     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_FORCE_PUSH);
195     ASSERT_NE(strategy, nullptr);
196     LogInfo localInfo;
197     LogInfo cloudInfo;
198 
199     /**
200      * @tc.steps: step2. local not exist cloud record
201      * @tc.expected: step2. not handle
202      */
203     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
204 
205     /**
206      * @tc.steps: step3. local has cloud record but don't have gid
207      * @tc.expected: step3. only update gid
208      */
209     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::ONLY_UPDATE_GID);
210 
211     /**
212      * @tc.steps: step4. local has cloud record and have gid
213      * @tc.expected: step4. not handle
214      */
215     localInfo.cloudGid = "gid";
216     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
217     localInfo.cloudGid = "";
218     /**
219      * @tc.steps: step5. local has cloud record(without gid) but cloud flag is delete
220      * @tc.expected: step5. ONLY UPDATE GID
221      */
222     cloudInfo.flag = 0x01; // it means delete
223     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
224     /**
225      * @tc.steps: step6. local has cloud record(with gid) but cloud flag is delete
226      * @tc.expected: step6. CLEAR_GID
227      */
228     localInfo.cloudGid = "gid";
229     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::CLEAR_GID);
230 }
231 
232 /**
233  * @tc.name: TagOpTyeTest003
234  * @tc.desc: Verify cloud cover local strategy tag operation type function.
235  * @tc.type: FUNC
236  * @tc.require:
237  * @tc.author: huangboxin
238  */
239 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest003, TestSize.Level0)
240 {
241     /**
242      * @tc.steps: step1. cloud cover local strategy
243      */
244     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_FORCE_PULL);
245     ASSERT_NE(strategy, nullptr);
246     LogInfo localInfo;
247     LogInfo cloudInfo;
248 
249     /**
250      * @tc.steps: step2. local not exist cloud record(without gid) and its not deleted in cloud
251      * @tc.expected: step2. insert
252      */
253     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::INSERT);
254 
255     /**
256      * @tc.steps: step3. local not exist cloud record and it's deleted in cloud (without gid)
257      * @tc.expected: step3. not handle
258      */
259     localInfo.cloudGid = "";
260     cloudInfo.flag = 0x01; // it means delete
261     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
262 
263     /**
264      * @tc.steps: step4. local not exist cloud record and it's deleted in cloud (with gid)
265      * @tc.expected: step4. delete
266      */
267     localInfo.cloudGid = "gid";
268     EXPECT_EQ(strategy->TagSyncDataStatus(false, false, localInfo, cloudInfo), OpType::DELETE);
269 
270     /**
271      * @tc.steps: step5. local exist cloud record and its deleted in cloud
272      * @tc.expected: step5. delete
273      */
274     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::DELETE);
275     localInfo.cloudGid = "";
276     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::DELETE);
277 
278     /**
279      * @tc.steps: step6. local exist cloud record and its not deleted in cloud(WITH OR WITHOUT gid)
280      * @tc.expected: step6. UPDATE
281      */
282     cloudInfo.flag = 0x00;
283     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
284     localInfo.cloudGid = "gid";
285     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
286 }
287 
288 /**
289  * @tc.name: TagOpTyeTest004
290  * @tc.desc: Verify cloud cover local strategy tag operation type function.
291  * @tc.type: FUNC
292  * @tc.require:
293  * @tc.author: huangboxin
294  */
295 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest004, TestSize.Level0)
296 {
297     /**
298      * @tc.steps: step1. cloud cover local strategy
299      */
300     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_FORCE_PULL);
301     ASSERT_NE(strategy, nullptr);
302     LogInfo localInfo;
303     LogInfo cloudInfo;
304 
305     cloudInfo.flag = 0x01;
306     localInfo.flag = 0x01;
307     localInfo.cloudGid = "";
308     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE_TIMESTAMP);
309 
310     cloudInfo.flag = 0x00;
311     localInfo.flag = 0x01;
312     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::INSERT);
313 }
314 
315 /**
316  * @tc.name: TagOpTyeTest005
317  * @tc.desc: Verify same data conflict in local.
318  * @tc.type: FUNC
319  * @tc.require:
320  * @tc.author: zhangqiquan
321  */
322 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest005, TestSize.Level0)
323 {
324     auto syncer = new(std::nothrow) VirtualCloudSyncer(nullptr);
325     ASSERT_NE(syncer, nullptr);
326     DataInfoWithLog localInfo;
327     LogInfo cloudInfo;
328     OpType result = OpType::INSERT;
329     EXPECT_EQ(syncer->CallTagStatusByStrategy(true, localInfo, cloudInfo, result), E_OK);
330     EXPECT_EQ(result, OpType::NOT_HANDLE);
331     localInfo.logInfo.device = "dev";
332     EXPECT_EQ(syncer->CallTagStatusByStrategy(true, localInfo, cloudInfo, result), -E_INTERNAL_ERROR);
333     RefObject::KillAndDecObjRef(syncer);
334 }
335 
336 /**
337  * @tc.name: TagOpTyeTest006
338  * @tc.desc: Verify cloud merge strategy for same record.
339  * @tc.type: FUNC
340  * @tc.require:
341  * @tc.author: zhangqiquan
342  */
343 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest006, TestSize.Level0)
344 {
345     /**
346      * @tc.steps: step1. create merge strategy
347      * @tc.expected: step1. create ok
348      */
349     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_MERGE);
350     ASSERT_NE(strategy, nullptr);
351     /**
352      * @tc.steps: step2. build cloud and local info, both has same version and diff timestamp
353      * @tc.expected: step2. strategy res is NOT_HANDLE
354      */
355     LogInfo localInfo;
356     LogInfo cloudInfo;
357     localInfo.cloudGid = "gid";
358     localInfo.version = "version";
359     localInfo.timestamp = 1;
360     cloudInfo.cloudGid = "gid";
361     cloudInfo.version = "version";
362     cloudInfo.timestamp = localInfo.timestamp + 1;
363     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
364     /**
365      * @tc.steps: step3. make timestamp gap is more than 1s
366      * @tc.expected: step3. strategy res is UPDATE
367      */
368     cloudInfo.timestamp = cloudInfo.timestamp + CloudDbConstant::ONE_SECOND;
369     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
370 }
371 
372 /**
373  * @tc.name: TagOpTyeTest007
374  * @tc.desc: Verify cloud merge strategy for KV and RDB scene when local time is larger and local flag different.
375  * @tc.type: FUNC
376  * @tc.require:
377  * @tc.author: suyue
378  */
379 HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest007, TestSize.Level0)
380 {
381     /**
382      * @tc.steps: step1. create merge strategy, init localInfo/cloudInfo and local time is larger
383      * @tc.expected: step1. create ok
384      */
385     auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_MERGE);
386     ASSERT_NE(strategy, nullptr);
387     LogInfo localInfo;
388     LogInfo cloudInfo;
389     localInfo.cloudGid = "gid";
390     localInfo.timestamp = 1u;
391 
392     /**
393      * @tc.steps: step2. local record is newer when flag is FLAG_LOCAL for RDB scene
394      * @tc.expected: step2. no need handle this record
395      */
396     localInfo.flag = static_cast<uint64_t>(LogInfoFlag::FLAG_LOCAL);
397     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
398 
399     /**
400      * @tc.steps: step3. local data need update when flag is not FLAG_LOCAL for RDB scene
401      * @tc.expected: step3. need UPDATE this record
402      */
403     localInfo.flag = 0x00;
404     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
405 
406     /**
407      * @tc.steps: step4. local record is newer when flag is not FLAG_CLOUD_WRITE for KV scene
408      * @tc.expected: step4. no need handle this record
409      */
410     strategy->SetIsKvScene(true);
411     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
412     localInfo.flag = 0x00;
413     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::NOT_HANDLE);
414 
415     /**
416      * @tc.steps: step5. local data need update when flag is FLAG_CLOUD_WRITE for KV scene
417      * @tc.expected: step5. need UPDATE this record
418      */
419     localInfo.flag = static_cast<uint64_t>(LogInfoFlag::FLAG_CLOUD_WRITE);
420     EXPECT_EQ(strategy->TagSyncDataStatus(true, false, localInfo, cloudInfo), OpType::UPDATE);
421 }
422 }