• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include <gtest/gtest.h>
17 
18 #include "cloud/cloud_storage_utils.h"
19 #include "cloud_store_types.h"
20 #include "db_common.h"
21 #include "distributeddb_data_generate_unit_test.h"
22 #include "distributeddb_tools_unit_test.h"
23 #include "icloud_sync_storage_interface.h"
24 #include "relational_store_instance.h"
25 #include "relational_store_manager.h"
26 #include "relational_sync_able_storage.h"
27 #include "sqlite_relational_store.h"
28 #include "storage_proxy.h"
29 #include "virtual_cloud_data_translate.h"
30 #include "runtime_config.h"
31 
32 
33 using namespace testing::ext;
34 using namespace  DistributedDB;
35 using namespace  DistributedDBUnitTest;
36 
37 namespace {
38     constexpr const char *DB_SUFFIX = ".db";
39     constexpr const char *STORE_ID = "Relational_Store_ID";
40     std::string g_dbDir;
41     std::string g_testDir;
42     std::string g_tableName = "sync_data";
43     std::string g_assetTableName = "asset_sync_data";
44     std::string g_storePath;
45     std::string g_gid = "abcd";
46     DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
47     IRelationalStore *g_store = nullptr;
48     RelationalStoreDelegate *g_delegate = nullptr;
49     ICloudSyncStorageInterface *g_cloudStore = nullptr;
50     constexpr const int64_t BASE_MODIFY_TIME = 12345678L;
51     constexpr const int64_t BASE_CREATE_TIME = 12345679L;
52 
53     enum class PrimaryKeyType {
54         NO_PRIMARY_KEY,
55         SINGLE_PRIMARY_KEY,
56         COMPOSITE_PRIMARY_KEY
57     };
58 
59     enum class GidType {
60         GID_EMPTY,
61         GID_MATCH,
62         GID_MISMATCH,
63         GID_INVALID
64     };
65 
66     class DistributedDBCloudSaveCloudDataTest : public testing::Test {
67     public:
68         static void SetUpTestCase(void);
69         static void TearDownTestCase(void);
70         void SetUp() override;
71         void TearDown() override;
72     };
73 
CreatDB()74     void CreatDB()
75     {
76         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
77         EXPECT_NE(db, nullptr);
78         EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
79         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
80     }
81 
SetCloudSchema(PrimaryKeyType pkType,bool nullable)82     void SetCloudSchema(PrimaryKeyType pkType, bool nullable)
83     {
84         TableSchema tableSchema;
85         bool isIdPk = pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY || pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY;
86         Field field1 = { "id", TYPE_INDEX<int64_t>, isIdPk, !isIdPk };
87         Field field2 = { "name", TYPE_INDEX<std::string>, pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY, true };
88         Field field3 = { "age", TYPE_INDEX<double>, false, true };
89         Field field4 = { "sex", TYPE_INDEX<bool>, false, nullable };
90         Field field5 = { "image", TYPE_INDEX<Bytes>, false, true };
91         tableSchema = { g_tableName, { field1, field2, field3, field4, field5} };
92 
93         DataBaseSchema dbSchema;
94         dbSchema.tables = { tableSchema };
95         g_cloudStore->SetCloudDbSchema(dbSchema);
96     }
97 
PrepareDataBase(const std::string & tableName,PrimaryKeyType pkType,bool nullable=true)98     void PrepareDataBase(const std::string &tableName, PrimaryKeyType pkType, bool nullable = true)
99     {
100         /**
101          * @tc.steps:step1. create table.
102          * @tc.expected: step1. return ok.
103          */
104         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
105         EXPECT_NE(db, nullptr);
106         std::string sql;
107         if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
108             sql = "create table " + tableName + "(id int primary key, name TEXT, age REAL, sex INTEGER, image BLOB);";
109         } else if (pkType == PrimaryKeyType::NO_PRIMARY_KEY) {
110             sql = "create table " + tableName + "(id int, name TEXT, age REAL, sex INTEGER, image BLOB);";
111         } else {
112             sql = "create table " + tableName + "(id int, name TEXT, age REAL, sex INTEGER, image BLOB," \
113                 " PRIMARY KEY(id, name))";
114         }
115         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
116 
117         /**
118          * @tc.steps:step2. create distributed table with CLOUD_COOPERATION mode.
119          * @tc.expected: step2. return ok.
120          */
121         EXPECT_EQ(g_delegate->CreateDistributedTable(tableName, DistributedDB::CLOUD_COOPERATION), OK);
122 
123         /**
124          * @tc.steps:step3. insert some row.
125          * @tc.expected: step3. return ok.
126          */
127         if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
128             sql = "insert into " + tableName + "(id, name, age)" \
129                 " values(1, 'zhangsan1', 10.1), (1, 'zhangsan2', 10.1), (2, 'zhangsan1', 10.0), (3, 'zhangsan3', 30),"
130                 " (4, 'zhangsan4', 40.123), (5, 'zhangsan5', 50.123);";
131         } else {
132             sql = "insert into " + tableName + "(id, name)" \
133                 " values(1, 'zhangsan1'), (2, 'zhangsan2'), (3, 'zhangsan3'), (4, 'zhangsan4'),"
134                 " (5, 'zhangsan5'), (6, 'zhangsan6'), (7, 'zhangsan7');";
135         }
136         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
137 
138         /**
139          * @tc.steps:step4. preset cloud gid.
140          * @tc.expected: step4. return ok.
141          */
142         for (int i = 0; i < 7; i++) { // update first 7 records
143             if (i == 4) { // 4 is id
144                 sql = "update " + DBCommon::GetLogTableName(tableName) + " set cloud_gid = '" +
145                     g_gid + std::to_string(i) + "', flag = 6 where data_key = " + std::to_string(i + 1);
146             } else {
147                 sql = "update " + DBCommon::GetLogTableName(tableName) + " set cloud_gid = '" +
148                     g_gid + std::to_string(i) + "' where data_key = " + std::to_string(i + 1);
149             }
150             EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
151             if (pkType != PrimaryKeyType::COMPOSITE_PRIMARY_KEY && i == 6) { // 6 is index
152                 sql = "delete from " + tableName + " where id = 7;";
153                 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
154             }
155         }
156 
157         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
158 
159         SetCloudSchema(pkType, nullable);
160     }
161 
InitStoreProp(const std::string & storePath,const std::string & appId,const std::string & userId,RelationalDBProperties & properties)162     void InitStoreProp(const std::string &storePath, const std::string &appId, const std::string &userId,
163         RelationalDBProperties &properties)
164     {
165         properties.SetStringProp(RelationalDBProperties::DATA_DIR, storePath);
166         properties.SetStringProp(RelationalDBProperties::APP_ID, appId);
167         properties.SetStringProp(RelationalDBProperties::USER_ID, userId);
168         properties.SetStringProp(RelationalDBProperties::STORE_ID, STORE_ID);
169         std::string identifier = userId + "-" + appId + "-" + STORE_ID;
170         std::string hashIdentifier = DBCommon::TransferHashString(identifier);
171         properties.SetStringProp(RelationalDBProperties::IDENTIFIER_DATA, hashIdentifier);
172     }
173 
GetRelationalStore()174     const RelationalSyncAbleStorage *GetRelationalStore()
175     {
176         RelationalDBProperties properties;
177         InitStoreProp(g_storePath, APP_ID, USER_ID, properties);
178         int errCode = E_OK;
179         g_store = RelationalStoreInstance::GetDataBase(properties, errCode);
180         if (g_store == nullptr) {
181             LOGE("Get db failed:%d", errCode);
182             return nullptr;
183         }
184         return static_cast<SQLiteRelationalStore *>(g_store)->GetStorageEngine();
185     }
186 
SetUpTestCase(void)187     void DistributedDBCloudSaveCloudDataTest::SetUpTestCase(void)
188     {
189         DistributedDBToolsUnitTest::TestDirInit(g_testDir);
190         LOGD("Test dir is %s", g_testDir.c_str());
191         g_dbDir = g_testDir + "/";
192         g_storePath = g_dbDir + STORE_ID + DB_SUFFIX;
193         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
194     }
195 
TearDownTestCase(void)196     void DistributedDBCloudSaveCloudDataTest::TearDownTestCase(void)
197     {
198     }
199 
SetUp()200     void DistributedDBCloudSaveCloudDataTest::SetUp()
201     {
202         CreatDB();
203         DBStatus status = g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, g_delegate);
204         EXPECT_EQ(status, OK);
205         ASSERT_NE(g_delegate, nullptr);
206         g_cloudStore = (ICloudSyncStorageInterface *) GetRelationalStore();
207         ASSERT_NE(g_cloudStore, nullptr);
208     }
209 
TearDown()210     void DistributedDBCloudSaveCloudDataTest::TearDown()
211     {
212         RefObject::DecObjRef(g_store);
213         EXPECT_EQ(g_mgr.CloseStore(g_delegate), OK);
214         g_delegate = nullptr;
215         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
216     }
217 
GetStorageProxy(ICloudSyncStorageInterface * store)218     std::shared_ptr<StorageProxy> GetStorageProxy(ICloudSyncStorageInterface *store)
219     {
220         return StorageProxy::GetCloudDb(store);
221     }
222 
GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType pkType,const std::string & gidStr,int64_t id,int expectCode,bool compositePkMatch=false)223     void GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType pkType, const std::string &gidStr, int64_t id,
224         int expectCode, bool compositePkMatch = false)
225     {
226         /**
227          * @tc.steps:step1. create db, create table.
228          * @tc.expected: step1. return ok.
229          */
230         PrepareDataBase(g_tableName, pkType);
231 
232         /**
233          * @tc.steps:step2. call GetInfoByPrimaryKeyOrGid.
234          * @tc.expected: step2. return expectCode.
235          */
236         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
237         ASSERT_NE(storageProxy, nullptr);
238         EXPECT_EQ(storageProxy->StartTransaction(), E_OK);
239         VBucket vBucket;
240         vBucket["id"] = id ;
241         if (compositePkMatch) {
242             std::string name = "zhangsan1";
243             vBucket["name"] = name;
244             vBucket["age"] = 10.1; // 10.1 is test age
245         } else {
246             std::string name = "zhangsan100";
247             vBucket["name"] = name;
248             vBucket["age"] = 10.11; // 10.11 is test age
249         }
250         vBucket[CloudDbConstant::GID_FIELD] = gidStr;
251         DataInfoWithLog dataInfoWithLog;
252         VBucket assetInfo;
253         EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), expectCode);
254         if (expectCode == E_OK) {
255             if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
256                 int64_t val = -1;
257                 // id is pk
258                 EXPECT_EQ(CloudStorageUtils::GetValueFromVBucket("id", dataInfoWithLog.primaryKeys, val), E_OK);
259             } else if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
260                 EXPECT_TRUE(dataInfoWithLog.primaryKeys.find("id") != dataInfoWithLog.primaryKeys.end());
261                 std::string name;
262                 EXPECT_EQ(CloudStorageUtils::GetValueFromVBucket("name", dataInfoWithLog.primaryKeys, name), E_OK);
263                 LOGD("name = %s", name.c_str());
264             } else {
265                 EXPECT_EQ(dataInfoWithLog.primaryKeys.size(), 0u);
266             }
267             Timestamp eraseTime = dataInfoWithLog.logInfo.timestamp / CloudDbConstant::TEN_THOUSAND *
268                 CloudDbConstant::TEN_THOUSAND;
269             Timestamp eraseWTime = dataInfoWithLog.logInfo.wTimestamp / CloudDbConstant::TEN_THOUSAND *
270                 CloudDbConstant::TEN_THOUSAND;
271             EXPECT_EQ(dataInfoWithLog.logInfo.timestamp, eraseTime);
272             EXPECT_EQ(dataInfoWithLog.logInfo.wTimestamp, eraseWTime);
273         }
274     }
275 
276     /**
277      * @tc.name: GetInfoByPrimaryKeyOrGidTest001
278      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = "", id = 100;
279      * @tc.type: FUNC
280      * @tc.require:
281      * @tc.author: zhangshijie
282      */
283     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest001, TestSize.Level0)
284     {
285         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, "", 100L, -E_NOT_FOUND);
286     }
287 
288     /**
289      * @tc.name: GetInfoByPrimaryKeyOrGidTest002
290      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = "", id = 1;
291      * @tc.type: FUNC
292      * @tc.require:
293      * @tc.author: zhangshijie
294      */
295     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest002, TestSize.Level0)
296     {
297         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, "", 1, E_OK);
298     }
299 
300     /**
301      * @tc.name: GetInfoByPrimaryKeyOrGidTest003
302      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd0, id = 100;
303      * @tc.type: FUNC
304      * @tc.require:
305      * @tc.author: zhangshijie
306      */
307     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest003, TestSize.Level0)
308     {
309         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(0), 100L, E_OK);
310     }
311 
312     /**
313      * @tc.name: GetInfoByPrimaryKeyOrGidTest004
314      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd0, id = 2, which will
315      * match two records;
316      * @tc.type: FUNC
317      * @tc.require:
318      * @tc.author: zhangshijie
319      */
320     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest004, TestSize.Level0)
321     {
322         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(0), 2L,
323             -E_CLOUD_ERROR);
324     }
325 
326     /**
327      * @tc.name: GetInfoByPrimaryKeyOrGidTest005
328      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd100, id = 100;
329      * @tc.type: FUNC
330      * @tc.require:
331      * @tc.author: zhangshijie
332      */
333     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest005, TestSize.Level0)
334     {
335         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(100), 100L,
336             -E_NOT_FOUND);
337     }
338 
339     /**
340      * @tc.name: GetInfoByPrimaryKeyOrGidTest006
341      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = abcd0, id = 100;
342      * @tc.type: FUNC
343      * @tc.require:
344      * @tc.author: zhangshijie
345      */
346     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest006, TestSize.Level0)
347     {
348         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, g_gid + std::to_string(0), 100L, E_OK);
349     }
350 
351     /**
352      * @tc.name: GetInfoByPrimaryKeyOrGidTest007
353      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = "", id = 1;
354      * @tc.type: FUNC
355      * @tc.require:
356      * @tc.author: zhangshijie
357      */
358     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest007, TestSize.Level0)
359     {
360         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, "", 1L, -E_CLOUD_ERROR);
361     }
362 
363     /**
364      * @tc.name: GetInfoByPrimaryKeyOrGidTest008
365      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = abcd100, id = 1;
366      * @tc.type: FUNC
367      * @tc.require:
368      * @tc.author: zhangshijie
369      */
370     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest008, TestSize.Level0)
371     {
372         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, g_gid + std::to_string(100), 1L,
373             -E_NOT_FOUND);
374     }
375 
376     /**
377      * @tc.name: GetInfoByPrimaryKeyOrGidTest009
378      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid = "", primary key match;
379      * @tc.type: FUNC
380      * @tc.require:
381      * @tc.author: zhangshijie
382      */
383     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest009, TestSize.Level0)
384     {
385         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "", 1L, E_OK, true);
386     }
387 
388     /**
389      * @tc.name: GetInfoByPrimaryKeyOrGidTest010
390      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid = "",
391      * primary key mismatch;
392      * @tc.type: FUNC
393      * @tc.require:
394      * @tc.author: zhangshijie
395      */
396     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest010, TestSize.Level0)
397     {
398         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "", 1L, -E_NOT_FOUND, false);
399     }
400 
401     /**
402      * @tc.name: GetInfoByPrimaryKeyOrGidTest011
403      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid match,
404      * primary key mismatch
405      * @tc.type: FUNC
406      * @tc.require:
407      * @tc.author: zhangshijie
408      */
409     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest011, TestSize.Level0)
410     {
411         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "abcd0", 11L, E_OK, false);
412     }
413 
VbucketWithoutPrimaryDataTest(PrimaryKeyType pkType)414     void VbucketWithoutPrimaryDataTest(PrimaryKeyType pkType)
415     {
416         /**
417          * @tc.steps:step1. create db, create table.
418          * @tc.expected: step1. return ok.
419          */
420         PrepareDataBase(g_tableName, pkType);
421 
422         /**
423          * @tc.steps:step2. call GetInfoByPrimaryKeyOrGid.
424          * @tc.expected: step2. return E_OK.
425          */
426         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
427         ASSERT_NE(storageProxy, nullptr);
428         EXPECT_EQ(storageProxy->StartTransaction(), E_OK);
429         VBucket vBucket;
430         std::string gid = g_gid + std::to_string(0);
431         vBucket[CloudDbConstant::GID_FIELD] = gid;
432         DataInfoWithLog dataInfoWithLog;
433         VBucket assetInfo;
434         EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), E_OK);
435     }
436 
437     /**
438      * @tc.name: GetInfoByPrimaryKeyOrGidTest012
439      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk data and gid match,
440      * @tc.type: FUNC
441      * @tc.require:
442      * @tc.author: zhangshijie
443      */
444     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest012, TestSize.Level0)
445     {
446         VbucketWithoutPrimaryDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
447     }
448 
449     /**
450      * @tc.name: GetInfoByPrimaryKeyOrGidTest013
451      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk(composite pk) data and gid match,
452      * @tc.type: FUNC
453      * @tc.require:
454      * @tc.author: zhangshijie
455      */
456     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest013, TestSize.Level0)
457     {
458         VbucketWithoutPrimaryDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
459     }
460 
ConstructDownloadData(DownloadData & downloadData,GidType gidType,bool nullable,bool vBucketContains)461     void ConstructDownloadData(DownloadData &downloadData, GidType gidType, bool nullable, bool vBucketContains)
462     {
463         for (int i = 0; i < 7; i++) { // 7 is record counts
464             VBucket vBucket;
465             if (i == 3) { // 3 is record index
466                 vBucket["id"] = 4L + i; // id = 5, 6 already pre_insert
467             } else {
468                 vBucket["id"] = 1L + i;
469             }
470 
471             std::string name = "lisi" + std::to_string(i);
472             vBucket["name"] = name;
473             vBucket["age"] = 100.0 + i; // 100.0 is offset for cloud data
474             if (vBucketContains) {
475                 vBucket["sex"] = i % 2 ? true : false; // 2 is mod
476             }
477 
478             vBucket["image"] = std::vector<uint8_t>(1, i);
479             std::string gid;
480             if (gidType == GidType::GID_MATCH) {
481                 gid = g_gid + std::to_string(i);
482             } else if (gidType == GidType::GID_EMPTY) {
483                 std::string emptyGid = "";
484                 gid = emptyGid;
485             } else if (gidType == GidType::GID_INVALID) {
486                 std::string invalidGid = "abc'd";
487                 gid = invalidGid;
488             } else {
489                 gid = std::to_string(i) + g_gid;
490             }
491 
492             vBucket[CloudDbConstant::GID_FIELD] = gid;
493             int64_t cTime = 12345678L + i;
494             vBucket[CloudDbConstant::CREATE_FIELD] = cTime;
495             int64_t mTime = 12345679L + i;
496             vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
497             downloadData.data.push_back(vBucket);
498         }
499 
500         downloadData.opType = { OpType::UPDATE, OpType::DELETE, OpType::ONLY_UPDATE_GID, OpType::INSERT,
501             OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO, OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE, OpType::NOT_HANDLE };
502     }
503 
SaveCloudDataTest(PrimaryKeyType pkType,GidType gidType=GidType::GID_MATCH,bool nullable=true,bool vBucketContains=true,int expectCode=E_OK)504     void SaveCloudDataTest(PrimaryKeyType pkType, GidType gidType = GidType::GID_MATCH, bool nullable = true,
505         bool vBucketContains = true, int expectCode = E_OK)
506     {
507         /**
508          * @tc.steps:step1. create db, create table.
509          * @tc.expected: step1. return ok.
510          */
511         PrepareDataBase(g_tableName, pkType, nullable);
512 
513         /**
514          * @tc.steps:step2. call PutCloudSyncData
515          * @tc.expected: step2. return ok.
516          */
517         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
518         ASSERT_NE(storageProxy, nullptr);
519         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
520 
521         DownloadData downloadData;
522         ConstructDownloadData(downloadData, gidType, nullable, vBucketContains);
523         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), expectCode);
524         if (expectCode == E_OK) {
525             for (size_t i = 0; i < downloadData.opType.size(); i++) {
526                 if (downloadData.opType[i] == OpType::INSERT) {
527                     EXPECT_TRUE(downloadData.data[i].find(CloudDbConstant::ROW_ID_FIELD_NAME) !=
528                         downloadData.data[i].end());
529                 }
530             }
531         }
532         EXPECT_EQ(storageProxy->Commit(), E_OK);
533     }
534 
535     /**
536      * @tc.name: PutCloudSyncDataTest001
537      * @tc.desc: Test save cloud data into table with no primary key, gid match
538      * @tc.type: FUNC
539      * @tc.require:
540      * @tc.author: zhangshijie
541      */
542     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest001, TestSize.Level0)
543     {
544         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY);
545         // there is one log record with cloud_gid = abcd3(id = 7 will delete first, then insert again)
546         std::string sql = "select count(data_key) from " + DBCommon::GetLogTableName(g_tableName) +
547             " where cloud_gid = '" + g_gid + std::to_string(3) + "'"; // 3 is gid index
548         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
549         EXPECT_NE(db, nullptr);
__anon417013e90202(sqlite3_stmt *stmt) 550         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [] (sqlite3_stmt *stmt) {
551             EXPECT_EQ(sqlite3_column_int64(stmt, 0), 1); // will get only 1 log record
552             return OK;
553         });
554         EXPECT_EQ(errCode, SQLITE_OK);
555         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
556     }
557 
558     /**
559      * @tc.name: PutCloudSyncDataTest002
560      * @tc.desc: Test save cloud data into table with no primary key, gid mismatch
561      * @tc.type: FUNC
562      * @tc.require:
563      * @tc.author: zhangshijie
564      */
565     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest002, TestSize.Level0)
566     {
567         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY, GidType::GID_MISMATCH);
568     }
569 
570     /**
571      * @tc.name: PutCloudSyncDataTest003
572      * @tc.desc: Test save cloud data into table with no primary key, gid is empty
573      * @tc.type: FUNC
574      * @tc.require:
575      * @tc.author: zhangshijie
576      */
577     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest003, TestSize.Level0)
578     {
579         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY, GidType::GID_EMPTY, true, true, -E_CLOUD_ERROR);
580     }
581 
582     /**
583      * @tc.name: PutCloudSyncDataTest004
584      * @tc.desc: Test save cloud data into table with single primary key, gid match
585      * @tc.type: FUNC
586      * @tc.require:
587      * @tc.author: zhangshijie
588      */
589     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest004, TestSize.Level0)
590     {
591         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
592     }
593 
594     /**
595      * @tc.name: PutCloudSyncDataTest005
596      * @tc.desc: Test save cloud data into table with single primary key, gid mismatch
597      * @tc.type: FUNC
598      * @tc.require:
599      * @tc.author: zhangshijie
600      */
601     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest005, TestSize.Level0)
602     {
603         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_MISMATCH);
604     }
605 
606     /**
607      * @tc.name: PutCloudSyncDataTest006
608      * @tc.desc: Test save cloud data into table with single primary key, gid is empty
609      * @tc.type: FUNC
610      * @tc.require:
611      * @tc.author: zhangshijie
612      */
613     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest006, TestSize.Level0)
614     {
615         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, true, true, -E_CLOUD_ERROR);
616     }
617 
618     /**
619      * @tc.name: PutCloudSyncDataTest007
620      * @tc.desc: Test save cloud data into table with single primary key, gid is empty, cloud field less than schema,
621      * field can be null
622      * @tc.type: FUNC
623      * @tc.require:
624      * @tc.author: zhangshijie
625      */
626     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest007, TestSize.Level0)
627     {
628         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_MATCH, true, false);
629     }
630 
631     /**
632      * @tc.name: PutCloudSyncDataTest008
633      * @tc.desc: Test save cloud data into table with single primary key, gid is empty, cloud field less than schema,
634      * field can not be null
635      * @tc.type: FUNC
636      * @tc.require:
637      * @tc.author: zhangshijie
638      */
639     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest008, TestSize.Level0)
640     {
641         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, false, false, -E_CLOUD_ERROR);
642     }
643 
644     /**
645      * @tc.name: PutCloudSyncDataTest009
646      * @tc.desc: Test save cloud data into table with composite primary key, gid match, primary key mismatch
647      * @tc.type: FUNC
648      * @tc.require:
649      * @tc.author: zhangshijie
650      */
651     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest009, TestSize.Level0)
652     {
653         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
654     }
655 
656     /**
657      * @tc.name: PutCloudSyncDataTest010
658      * @tc.desc: Test save cloud data into table with composite primary key, gid mismatch, primary key mismatch
659      * @tc.type: FUNC
660      * @tc.require:
661      * @tc.author: zhangshijie
662      */
663     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest010, TestSize.Level0)
664     {
665         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, GidType::GID_MISMATCH);
666     }
667 
668     /**
669      * @tc.name: PutCloudSyncDataTest011
670      * @tc.desc: Test save cloud data into table with composite primary key, invalid gid
671      * @tc.type: FUNC
672      * @tc.require:
673      * @tc.author: zhangshijie
674      */
675     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest011, TestSize.Level0)
676     {
677         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, GidType::GID_INVALID, true, true, -E_CLOUD_ERROR);
678     }
679 
ConstructMultiDownloadData(DownloadData & downloadData,GidType gidType)680     void ConstructMultiDownloadData(DownloadData &downloadData, GidType gidType)
681     {
682         for (int i = 0; i < 6; i++) { // 6 is record counts
683             VBucket vBucket;
684             if (i < 1) { // UPDATE_TIMESTAMP doesn't contain pk
685                 vBucket["id"] = 1L + i;
686             } else if (i > 1) {
687                 vBucket["id"] = 10L + i; // 10 is id offset for cloud data
688             }
689 
690             std::string name = "lisi" + std::to_string(i);
691             vBucket["name"] = name;
692             vBucket["age"] = 100.0 + i; // 100.0 is offset for cloud data
693             vBucket["sex"] = i % 2 ? true : false; // 2 is mod
694 
695             vBucket["image"] = std::vector<uint8_t>(1, i);
696             std::string gid;
697             if (gidType == GidType::GID_MATCH) {
698                 if (i <= 1) { // first 2 exists in local
699                     gid = g_gid + std::to_string(i);
700                 } else {
701                     gid = g_gid + std::to_string(10 + i); // 10 is id offset for cloud data
702                 }
703             } else if (gidType == GidType::GID_EMPTY) {
704                 std::string emptyGid = "";
705                 gid = emptyGid;
706             } else {
707                 gid = std::to_string(i) + g_gid;
708             }
709 
710             vBucket[CloudDbConstant::GID_FIELD] = gid;
711             int64_t cTime = BASE_CREATE_TIME + i;
712             vBucket[CloudDbConstant::CREATE_FIELD] = cTime;
713             int64_t mTime = BASE_MODIFY_TIME + i;
714             vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
715             downloadData.data.push_back(vBucket);
716         }
717 
718         downloadData.opType = { OpType::UPDATE, OpType::UPDATE_TIMESTAMP, OpType::INSERT, OpType::INSERT,
719             OpType::INSERT, OpType::NOT_HANDLE };
720     }
721 
722     /**
723      * @tc.name: PutCloudSyncDataTest012
724      * @tc.desc: Test save cloud data into table with no primary key, multi cloud data
725      * @tc.type: FUNC
726      * @tc.require:
727      * @tc.author: zhangshijie
728      */
729     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest012, TestSize.Level0)
730     {
731         /**
732          * @tc.steps:step1. create db, create table.
733          * @tc.expected: step1. return ok.
734          */
735         PrepareDataBase(g_tableName, PrimaryKeyType::NO_PRIMARY_KEY, true);
736 
737         /**
738          * @tc.steps:step2. call PutCloudSyncData
739          * @tc.expected: step2. return ok.
740          */
741         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
742         ASSERT_NE(storageProxy, nullptr);
743         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
744 
745         DownloadData downloadData;
746         ConstructMultiDownloadData(downloadData, GidType::GID_MATCH);
747         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
748         EXPECT_EQ(storageProxy->Commit(), E_OK);
749     }
750 
751     /**
752      * @tc.name: PutCloudSyncDataTest013
753      * @tc.desc: Test save cloud data with type = update_timestamp
754      * @tc.type: FUNC
755      * @tc.require:
756      * @tc.author: zhangshijie
757      */
758     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest013, TestSize.Level0)
759     {
760         /**
761          * @tc.steps:step1. create db, create table.
762          * @tc.expected: step1. return ok.
763          */
764         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY, true);
765 
766         std::string sql = "delete from " + g_tableName + " where id = 2";
767         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
768         EXPECT_NE(db, nullptr);
769         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
770         /**
771          * @tc.steps:step2. call PutCloudSyncData
772          * @tc.expected: step2. return ok.
773          */
774         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
775         ASSERT_NE(storageProxy, nullptr);
776         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
777 
778         DownloadData downloadData;
779         ConstructMultiDownloadData(downloadData, GidType::GID_MATCH);
780         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
781         EXPECT_EQ(storageProxy->Commit(), E_OK);
782 
783         /**
784          * @tc.steps:step3. verify data
785          * @tc.expected: step3. verify data ok.
786          */
787         sql = "select device, timestamp, flag from " + DBCommon::GetLogTableName(g_tableName) +
788             " where data_key = -1 and cloud_gid = ''";
789         int count = 0;
__anon417013e90302(sqlite3_stmt *stmt) 790         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
791             std::string device = "cloud";
792             std::vector<uint8_t> deviceVec;
793             (void)SQLiteUtils::GetColumnBlobValue(stmt, 0, deviceVec);    // 0 is device
794             std::string getDevice;
795             DBCommon::VectorToString(deviceVec, getDevice);
796             EXPECT_EQ(device, getDevice);
797             EXPECT_EQ(sqlite3_column_int64(stmt, 1), BASE_MODIFY_TIME + 1);
798             EXPECT_EQ(sqlite3_column_int(stmt, 2), 1); // 2 is flag
799             count++;
800             return OK;
801         });
802         EXPECT_EQ(errCode, E_OK);
803         EXPECT_EQ(count, 1);
804         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
805     }
806 
807     /**
808      * @tc.name: PutCloudSyncDataTest014
809      * @tc.desc: Test PutCloudSyncData when vbucket doesn't contain pk data and gid match,
810      * @tc.type: FUNC
811      * @tc.require:
812      * @tc.author: zhangshijie
813      */
814     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest014, TestSize.Level0)
815     {
816         /**
817          * @tc.steps:step1. create db, create table.
818          * @tc.expected: step1. return ok.
819          */
820         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY);
821 
822         /**
823          * @tc.steps:step2. construct data without primary key value, call PutCloudSyncData.
824          * @tc.expected: step2. return E_OK.
825          */
826         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
827         ASSERT_NE(storageProxy, nullptr);
828         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
829 
830         DownloadData downloadData;
831         VBucket vBucket;
832         std::string gid = g_gid + std::to_string(0);
833         vBucket[CloudDbConstant::GID_FIELD] = gid;
834         vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
835         downloadData.data.push_back(vBucket);
836         downloadData.opType = { OpType::DELETE };
837         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
838         EXPECT_EQ(storageProxy->Commit(), E_OK);
839     }
840 
841     /**
842      * @tc.name: PutCloudSyncDataTest015
843      * @tc.desc: Test clear gid and ONLY_UPDATE_GID
844      * @tc.type: FUNC
845      * @tc.require:
846      * @tc.author: zhangshijie
847      */
848     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest015, TestSize.Level0)
849     {
850         /**
851          * @tc.steps:step1. create db, create table.
852          * @tc.expected: step1. return ok.
853          */
854         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY);
855 
856         /**
857          * @tc.steps:step2. construct data type = clear_gid, call PutCloudSyncData.
858          * @tc.expected: step2. return E_OK.
859          */
860         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
861         ASSERT_NE(storageProxy, nullptr);
862         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
863 
864         DownloadData downloadData;
865         for (int i = 0; i < 2; i++) { // 2 is record count
866             VBucket vBucket;
867             std::string gid = g_gid + std::to_string(i * 4); // 4 is data index
868             vBucket[CloudDbConstant::GID_FIELD] = gid;
869             vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
870             downloadData.data.push_back(vBucket);
871         }
872         downloadData.opType = { OpType::ONLY_UPDATE_GID, OpType::CLEAR_GID };
873         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
874         EXPECT_EQ(storageProxy->Commit(), E_OK);
875 
876         /**
877          * @tc.steps:step3. verify data
878          * @tc.expected: step3. verify data ok.
879          */
880         std::string sql = "select cloud_gid, flag from " + DBCommon::GetLogTableName(g_tableName) +
881             " where data_key = 1 or data_key = 5";
882         int count = 0;
883         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
884         EXPECT_NE(db, nullptr);
__anon417013e90402(sqlite3_stmt *stmt) 885         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
886             std::string gid = "";
887             if (count == 0) {
888                 gid = g_gid + "0";
889             }
890             const unsigned char *val = sqlite3_column_text(stmt, 0);
891             EXPECT_TRUE(val != nullptr);
892             std::string getGid = reinterpret_cast<const char *>(val);
893             LOGD("GET GID = %s", getGid.c_str());
894             EXPECT_EQ(getGid, gid);
895             if (count == 1) {
896                 int flag = sqlite3_column_int(stmt, 1);
897                 EXPECT_EQ(flag & 0x04, 0); // 0x04 is binay num of b100, clear gid will clear 2th bit of flag
898             }
899             count++;
900             return OK;
901         });
902         EXPECT_EQ(errCode, E_OK);
903         EXPECT_EQ(count, 2); // 2 is result count
904         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
905     }
906 
DeleteWithPkTest(PrimaryKeyType pkType)907     void DeleteWithPkTest(PrimaryKeyType pkType)
908     {
909         /**
910          * @tc.steps:step1. create db, create table.
911          * @tc.expected: step1. return ok.
912          */
913         PrepareDataBase(g_tableName, pkType, false);
914 
915         /**
916          * @tc.steps:step2. call PutCloudSyncData
917          * @tc.expected: step2. return ok.
918          */
919         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
920         ASSERT_NE(storageProxy, nullptr);
921         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
922 
923         DownloadData downloadData;
924         VBucket vBucket;
925         vBucket["id"] = 1L;
926         if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
927             std::string name = "zhangsan1";
928             vBucket["name"] = name;
929         }
930 
931         std::string gid = g_gid + "_not_exist"; // gid mismatch
932         vBucket[CloudDbConstant::GID_FIELD] = gid;
933         vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
934         downloadData.data.push_back(vBucket);
935         downloadData.opType = { OpType::DELETE };
936         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
937         EXPECT_EQ(storageProxy->Commit(), E_OK);
938 
939         /**
940          * @tc.steps:step3. verify data
941          * @tc.expected: step3. verify data ok.
942          */
943         std::string sql;
944         if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
945             sql = "select count(1) from " + g_tableName + " where id = 1";
946         } else {
947             sql = "select count(1) from " + g_tableName + " where id = 1 and name = 'zhangsan'";
948         }
949         int count = 0;
950         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
951         EXPECT_NE(db, nullptr);
952         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
953             EXPECT_EQ(sqlite3_column_int(stmt, 0), 0);
954             count++;
955             return OK;
956         });
957         EXPECT_EQ(errCode, E_OK);
958         EXPECT_EQ(count, 1);
959         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
960     }
961 
962     /**
963      * @tc.name: PutCloudSyncDataTest016
964      * @tc.desc: Test delete data with pk in cloud data(normally there is no pk in cloud data when it is delete)
965      * @tc.type: FUNC
966      * @tc.require:
967      * @tc.author: zhangshijie
968      */
969     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest016, TestSize.Level1)
970     {
971         DeleteWithPkTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
972     }
973 
974     /**
975      * @tc.name: PutCloudSyncDataTest017
976      * @tc.desc: Test delete data with pk in cloud data(normally there is no pk in cloud data when it is delete)
977      * primary key is COMPOSITE_PRIMARY_KEY
978      * @tc.type: FUNC
979      * @tc.require:
980      * @tc.author: zhangshijie
981      */
982     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest017, TestSize.Level1)
983     {
984         DeleteWithPkTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
985     }
986 
987     /**
988      * @tc.name: DropTableTest001
989      * @tc.desc: Test drop table
990      * @tc.type: FUNC
991      * @tc.require:
992      * @tc.author: zhangshijie
993      */
994     HWTEST_F(DistributedDBCloudSaveCloudDataTest, DropTableTest001, TestSize.Level1)
995     {
996         /**
997          * @tc.steps:step1. create db, create table, prepare data.
998          * @tc.expected: step1. ok.
999          */
1000         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1001         EXPECT_NE(db, nullptr);
1002         EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
1003 
1004         std::string sql = "create table t_device(key int, value text);create table t_cloud(key int, value text);";
1005         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1006         EXPECT_EQ(g_delegate->CreateDistributedTable("t_device", DistributedDB::DEVICE_COOPERATION), OK);
1007         EXPECT_EQ(g_delegate->CreateDistributedTable("t_cloud", DistributedDB::CLOUD_COOPERATION), OK);
1008 
1009         sql = "insert into t_device values(1, 'zhangsan');insert into t_cloud values(1, 'zhangsan');";
1010         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1011         sql = "update " + DBCommon::GetLogTableName("t_cloud") + " set flag = 0";
1012         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1013         return;
1014 
1015         /**
1016          * @tc.steps:step2. drop table t_cloud, check log data
1017          * @tc.expected: step2. success.
1018          */
1019         sql = "drop table t_cloud;";
1020         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1021         sql = "select flag from " + DBCommon::GetLogTableName("t_cloud") + " where data_key = -1;";
1022         int count = 0;
__anon417013e90602(sqlite3_stmt *stmt) 1023         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1024             EXPECT_EQ(sqlite3_column_int(stmt, 0), 3); // 3 mean local delete
1025             count++;
1026             return OK;
1027         });
1028         EXPECT_EQ(errCode, E_OK);
1029         EXPECT_EQ(count, 1);
1030 
1031         /**
1032          * @tc.steps:step3. drop table t_device, check log data
1033          * @tc.expected: step3. success.
1034          */
1035         sql = "drop table t_device;";
1036         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1037         sql = "select flag from " + DBCommon::GetLogTableName("t_device") + " where flag = 0x03;";
1038         count = 0;
__anon417013e90702(sqlite3_stmt *stmt) 1039         errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1040             count++;
1041             return OK;
1042         });
1043         EXPECT_EQ(errCode, E_OK);
1044         EXPECT_EQ(count, 1);
1045         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
1046     }
1047 }
1048