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 "mock_relational_sync_able_storage.h"
25 #include "relational_store_instance.h"
26 #include "relational_store_manager.h"
27 #include "relational_sync_able_storage.h"
28 #include "runtime_config.h"
29 #include "sqlite_relational_store.h"
30 #include "storage_proxy.h"
31 #include "virtual_cloud_data_translate.h"
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,bool asset=false)82     void SetCloudSchema(PrimaryKeyType pkType, bool nullable, bool asset = false)
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;
91         if (asset) {
92             field5 = { "image", TYPE_INDEX<Asset>, false, true };
93         } else {
94             field5 = { "image", TYPE_INDEX<Bytes>, false, true };
95         }
96         tableSchema = { g_tableName, g_tableName + "_shared", { field1, field2, field3, field4, field5} };
97         DataBaseSchema dbSchema;
98         dbSchema.tables.push_back(tableSchema);
99         tableSchema = { g_assetTableName, g_assetTableName + "_shared", { field1, field2, field3, field4, field5} };
100         dbSchema.tables.push_back(tableSchema);
101 
102         g_delegate->SetCloudDbSchema(dbSchema);
103     }
104 
PrepareDataBase(const std::string & tableName,PrimaryKeyType pkType,bool nullable=true)105     void PrepareDataBase(const std::string &tableName, PrimaryKeyType pkType, bool nullable = true)
106     {
107         /**
108          * @tc.steps:step1. create table.
109          * @tc.expected: step1. return ok.
110          */
111         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
112         EXPECT_NE(db, nullptr);
113         std::string sql;
114         if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
115             sql = "create table " + tableName + "(id int primary key, name TEXT, age REAL, sex INTEGER, image BLOB);";
116         } else if (pkType == PrimaryKeyType::NO_PRIMARY_KEY) {
117             sql = "create table " + tableName + "(id int, name TEXT, age REAL, sex INTEGER, image BLOB);";
118         } else {
119             sql = "create table " + tableName + "(id int, name TEXT, age REAL, sex INTEGER, image BLOB," \
120                 " PRIMARY KEY(id, name))";
121         }
122         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
123 
124         /**
125          * @tc.steps:step2. create distributed table with CLOUD_COOPERATION mode.
126          * @tc.expected: step2. return ok.
127          */
128         EXPECT_EQ(g_delegate->CreateDistributedTable(tableName, DistributedDB::CLOUD_COOPERATION), OK);
129 
130         /**
131          * @tc.steps:step3. insert some row.
132          * @tc.expected: step3. return ok.
133          */
134         if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
135             sql = "insert into " + tableName + "(id, name, age)" \
136                 " values(1, 'zhangsan1', 10.1), (1, 'zhangsan2', 10.1), (2, 'zhangsan1', 10.0), (3, 'zhangsan3', 30),"
137                 " (4, 'zhangsan4', 40.123), (5, 'zhangsan5', 50.123);";
138         } else {
139             sql = "insert into " + tableName + "(id, name)" \
140                 " values(1, 'zhangsan1'), (2, 'zhangsan2'), (3, 'zhangsan3'), (4, 'zhangsan4'),"
141                 " (5, 'zhangsan5'), (6, 'zhangsan6'), (7, 'zhangsan7');";
142         }
143         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
144 
145         /**
146          * @tc.steps:step4. preset cloud gid.
147          * @tc.expected: step4. return ok.
148          */
149         for (int i = 0; i < 7; i++) { // update first 7 records
150             if (i == 4) { // 4 is id
151                 sql = "update " + DBCommon::GetLogTableName(tableName) + " set cloud_gid = '" +
152                     g_gid + std::to_string(i) + "', flag = 6 where data_key = " + std::to_string(i + 1);
153             } else {
154                 sql = "update " + DBCommon::GetLogTableName(tableName) + " set cloud_gid = '" +
155                     g_gid + std::to_string(i) + "' where data_key = " + std::to_string(i + 1);
156             }
157             EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
158             if (pkType != PrimaryKeyType::COMPOSITE_PRIMARY_KEY && i == 6) { // 6 is index
159                 sql = "delete from " + tableName + " where id = 7;";
160                 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
161             }
162         }
163 
164         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
165 
166         SetCloudSchema(pkType, nullable);
167     }
168 
PrepareDataBaseForAsset(const std::string & tableName,bool nullable=true)169     void PrepareDataBaseForAsset(const std::string &tableName, bool nullable = true)
170     {
171         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
172         EXPECT_NE(db, nullptr);
173         std::string sql =
174             "create table " + tableName + "(id int, name TEXT, age REAL, sex INTEGER, image BLOB);";
175         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
176         EXPECT_EQ(g_delegate->CreateDistributedTable(tableName, DistributedDB::CLOUD_COOPERATION), OK);
177 
178         sql = "insert into " + tableName + "(id, name, image) values(1, 'zhangsan1', ?);";
179         sqlite3_stmt *stmt = nullptr;
180         EXPECT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), SQLITE_OK);
181         Asset asset;
182         asset.name = "123";
183         asset.status = static_cast<uint32_t>(AssetStatus::ABNORMAL);
184         VirtualCloudDataTranslate translate;
185         Bytes bytes = translate.AssetToBlob(asset);
186         EXPECT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, bytes), E_OK);
187         EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
188         int errCode = E_OK;
189         SQLiteUtils::ResetStatement(stmt, true, errCode);
190 
191         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
192         SetCloudSchema(PrimaryKeyType::NO_PRIMARY_KEY, nullable, true);
193     }
194 
InitStoreProp(const std::string & storePath,const std::string & appId,const std::string & userId,RelationalDBProperties & properties)195     void InitStoreProp(const std::string &storePath, const std::string &appId, const std::string &userId,
196         RelationalDBProperties &properties)
197     {
198         properties.SetStringProp(RelationalDBProperties::DATA_DIR, storePath);
199         properties.SetStringProp(RelationalDBProperties::APP_ID, appId);
200         properties.SetStringProp(RelationalDBProperties::USER_ID, userId);
201         properties.SetStringProp(RelationalDBProperties::STORE_ID, STORE_ID);
202         std::string identifier = userId + "-" + appId + "-" + STORE_ID;
203         std::string hashIdentifier = DBCommon::TransferHashString(identifier);
204         properties.SetStringProp(RelationalDBProperties::IDENTIFIER_DATA, hashIdentifier);
205     }
206 
GetRelationalStore()207     const RelationalSyncAbleStorage *GetRelationalStore()
208     {
209         RelationalDBProperties properties;
210         InitStoreProp(g_storePath, APP_ID, USER_ID, properties);
211         int errCode = E_OK;
212         g_store = RelationalStoreInstance::GetDataBase(properties, errCode);
213         if (g_store == nullptr) {
214             LOGE("Get db failed:%d", errCode);
215             return nullptr;
216         }
217         return static_cast<SQLiteRelationalStore *>(g_store)->GetStorageEngine();
218     }
219 
SetUpTestCase(void)220     void DistributedDBCloudSaveCloudDataTest::SetUpTestCase(void)
221     {
222         DistributedDBToolsUnitTest::TestDirInit(g_testDir);
223         LOGD("Test dir is %s", g_testDir.c_str());
224         g_dbDir = g_testDir + "/";
225         g_storePath = g_dbDir + STORE_ID + DB_SUFFIX;
226         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
227     }
228 
TearDownTestCase(void)229     void DistributedDBCloudSaveCloudDataTest::TearDownTestCase(void)
230     {
231     }
232 
SetUp()233     void DistributedDBCloudSaveCloudDataTest::SetUp()
234     {
235         CreatDB();
236         DBStatus status = g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, g_delegate);
237         EXPECT_EQ(status, OK);
238         ASSERT_NE(g_delegate, nullptr);
239         g_cloudStore = (ICloudSyncStorageInterface *) GetRelationalStore();
240         ASSERT_NE(g_cloudStore, nullptr);
241     }
242 
TearDown()243     void DistributedDBCloudSaveCloudDataTest::TearDown()
244     {
245         RefObject::DecObjRef(g_store);
246         EXPECT_EQ(g_mgr.CloseStore(g_delegate), OK);
247         g_delegate = nullptr;
248         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
249     }
250 
GetStorageProxy(ICloudSyncStorageInterface * store)251     std::shared_ptr<StorageProxy> GetStorageProxy(ICloudSyncStorageInterface *store)
252     {
253         return StorageProxy::GetCloudDb(store);
254     }
255 
GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType pkType,const std::string & gidStr,int64_t id,int expectCode,bool compositePkMatch=false)256     void GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType pkType, const std::string &gidStr, int64_t id,
257         int expectCode, bool compositePkMatch = false)
258     {
259         /**
260          * @tc.steps:step1. create db, create table.
261          * @tc.expected: step1. return ok.
262          */
263         PrepareDataBase(g_tableName, pkType);
264 
265         /**
266          * @tc.steps:step2. call GetInfoByPrimaryKeyOrGid.
267          * @tc.expected: step2. return expectCode.
268          */
269         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
270         ASSERT_NE(storageProxy, nullptr);
271         EXPECT_EQ(storageProxy->StartTransaction(), E_OK);
272         VBucket vBucket;
273         vBucket["id"] = id ;
274         if (compositePkMatch) {
275             std::string name = "zhangsan1";
276             vBucket["name"] = name;
277             vBucket["age"] = 10.1; // 10.1 is test age
278         } else {
279             std::string name = "zhangsan100";
280             vBucket["name"] = name;
281             vBucket["age"] = 10.11; // 10.11 is test age
282         }
283         vBucket[CloudDbConstant::GID_FIELD] = gidStr;
284         DataInfoWithLog dataInfoWithLog;
285         VBucket assetInfo;
286         EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), expectCode);
287         if (expectCode == E_OK) {
288             if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
289                 int64_t val = -1;
290                 // id is pk
291                 EXPECT_EQ(CloudStorageUtils::GetValueFromVBucket("id", dataInfoWithLog.primaryKeys, val), E_OK);
292             } else if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
293                 EXPECT_TRUE(dataInfoWithLog.primaryKeys.find("id") != dataInfoWithLog.primaryKeys.end());
294                 std::string name;
295                 EXPECT_EQ(CloudStorageUtils::GetValueFromVBucket("name", dataInfoWithLog.primaryKeys, name), E_OK);
296                 LOGD("name = %s", name.c_str());
297             } else {
298                 EXPECT_EQ(dataInfoWithLog.primaryKeys.size(), 0u);
299             }
300             Timestamp eraseTime = dataInfoWithLog.logInfo.timestamp / CloudDbConstant::TEN_THOUSAND *
301                 CloudDbConstant::TEN_THOUSAND;
302             Timestamp eraseWTime = dataInfoWithLog.logInfo.wTimestamp / CloudDbConstant::TEN_THOUSAND *
303                 CloudDbConstant::TEN_THOUSAND;
304             EXPECT_EQ(dataInfoWithLog.logInfo.timestamp, eraseTime);
305             EXPECT_EQ(dataInfoWithLog.logInfo.wTimestamp, eraseWTime);
306         }
307         EXPECT_EQ(storageProxy->Commit(), E_OK);
308     }
309 
310     /**
311      * @tc.name: GetInfoByPrimaryKeyOrGidTest001
312      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = "", id = 100;
313      * @tc.type: FUNC
314      * @tc.require:
315      * @tc.author: zhangshijie
316      */
317     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest001, TestSize.Level0)
318     {
319         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, "", 100L, -E_NOT_FOUND);
320     }
321 
322     /**
323      * @tc.name: GetInfoByPrimaryKeyOrGidTest002
324      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = "", id = 1;
325      * @tc.type: FUNC
326      * @tc.require:
327      * @tc.author: zhangshijie
328      */
329     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest002, TestSize.Level0)
330     {
331         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, "", 1, E_OK);
332     }
333 
334     /**
335      * @tc.name: GetInfoByPrimaryKeyOrGidTest003
336      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd0, id = 100;
337      * @tc.type: FUNC
338      * @tc.require:
339      * @tc.author: zhangshijie
340      */
341     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest003, TestSize.Level0)
342     {
343         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(0), 100L, E_OK);
344     }
345 
346     /**
347      * @tc.name: GetInfoByPrimaryKeyOrGidTest004
348      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd0, id = 2, which will
349      * match two records;
350      * @tc.type: FUNC
351      * @tc.require:
352      * @tc.author: zhangshijie
353      */
354     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest004, TestSize.Level0)
355     {
356         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(0), 2L,
357             -E_CLOUD_ERROR);
358     }
359 
360     /**
361      * @tc.name: GetInfoByPrimaryKeyOrGidTest005
362      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has single primary key and gid = abcd100, id = 100;
363      * @tc.type: FUNC
364      * @tc.require:
365      * @tc.author: zhangshijie
366      */
367     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest005, TestSize.Level0)
368     {
369         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, g_gid + std::to_string(100), 100L,
370             -E_NOT_FOUND);
371     }
372 
373     /**
374      * @tc.name: GetInfoByPrimaryKeyOrGidTest006
375      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = abcd0, id = 100;
376      * @tc.type: FUNC
377      * @tc.require:
378      * @tc.author: zhangshijie
379      */
380     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest006, TestSize.Level0)
381     {
382         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, g_gid + std::to_string(0), 100L, E_OK);
383     }
384 
385     /**
386      * @tc.name: GetInfoByPrimaryKeyOrGidTest007
387      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = "", id = 1;
388      * @tc.type: FUNC
389      * @tc.require:
390      * @tc.author: zhangshijie
391      */
392     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest007, TestSize.Level0)
393     {
394         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, "", 1L, -E_CLOUD_ERROR);
395     }
396 
397     /**
398      * @tc.name: GetInfoByPrimaryKeyOrGidTest008
399      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has no primary key and gid = abcd100, id = 1;
400      * @tc.type: FUNC
401      * @tc.require:
402      * @tc.author: zhangshijie
403      */
404     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest008, TestSize.Level0)
405     {
406         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::NO_PRIMARY_KEY, g_gid + std::to_string(100), 1L,
407             -E_NOT_FOUND);
408     }
409 
410     /**
411      * @tc.name: GetInfoByPrimaryKeyOrGidTest009
412      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid = "", primary key match;
413      * @tc.type: FUNC
414      * @tc.require:
415      * @tc.author: zhangshijie
416      */
417     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest009, TestSize.Level0)
418     {
419         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "", 1L, E_OK, true);
420     }
421 
422     /**
423      * @tc.name: GetInfoByPrimaryKeyOrGidTest010
424      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid = "",
425      * primary key mismatch;
426      * @tc.type: FUNC
427      * @tc.require:
428      * @tc.author: zhangshijie
429      */
430     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest010, TestSize.Level0)
431     {
432         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "", 1L, -E_NOT_FOUND, false);
433     }
434 
435     /**
436      * @tc.name: GetInfoByPrimaryKeyOrGidTest011
437      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid match,
438      * primary key mismatch
439      * @tc.type: FUNC
440      * @tc.require:
441      * @tc.author: zhangshijie
442      */
443     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest011, TestSize.Level0)
444     {
445         GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "abcd0", 11L, E_OK, false);
446     }
447 
VbucketWithoutPrimaryDataTest(PrimaryKeyType pkType)448     void VbucketWithoutPrimaryDataTest(PrimaryKeyType pkType)
449     {
450         /**
451          * @tc.steps:step1. create db, create table.
452          * @tc.expected: step1. return ok.
453          */
454         PrepareDataBase(g_tableName, pkType);
455 
456         /**
457          * @tc.steps:step2. call GetInfoByPrimaryKeyOrGid.
458          * @tc.expected: step2. return E_OK.
459          */
460         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
461         ASSERT_NE(storageProxy, nullptr);
462         EXPECT_EQ(storageProxy->StartTransaction(), E_OK);
463         VBucket vBucket;
464         std::string gid = g_gid + std::to_string(0);
465         vBucket[CloudDbConstant::GID_FIELD] = gid;
466         DataInfoWithLog dataInfoWithLog;
467         VBucket assetInfo;
468         EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), E_OK);
469         EXPECT_EQ(storageProxy->Commit(), E_OK);
470     }
471 
472     /**
473      * @tc.name: GetInfoByPrimaryKeyOrGidTest012
474      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk data and gid match,
475      * @tc.type: FUNC
476      * @tc.require:
477      * @tc.author: zhangshijie
478      */
479     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest012, TestSize.Level0)
480     {
481         VbucketWithoutPrimaryDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
482     }
483 
484     /**
485      * @tc.name: GetInfoByPrimaryKeyOrGidTest013
486      * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk(composite pk) data and gid match,
487      * @tc.type: FUNC
488      * @tc.require:
489      * @tc.author: zhangshijie
490      */
491     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest013, TestSize.Level0)
492     {
493         VbucketWithoutPrimaryDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
494     }
495 
SetCloudSchemaForCollate(bool ageIsPrimaryKey)496     void SetCloudSchemaForCollate(bool ageIsPrimaryKey)
497     {
498         TableSchema tableSchema;
499         Field field1 = { "name", TYPE_INDEX<std::string>, true, false };
500         Field field2 = { "age", TYPE_INDEX<std::string>, ageIsPrimaryKey, false };
501         tableSchema = { g_tableName, g_tableName + "_shared", { field1, field2 } };
502 
503         DataBaseSchema dbSchema;
504         dbSchema.tables = { tableSchema };
505         g_delegate->SetCloudDbSchema(dbSchema);
506     }
507 
PrimaryKeyCollateTest(const std::string & createSql,const std::string & insertSql,const std::vector<std::string> & pkStr,bool ageIsPrimaryKey,int expectCode=E_OK)508     void PrimaryKeyCollateTest(const std::string &createSql, const std::string &insertSql,
509         const std::vector<std::string> &pkStr, bool ageIsPrimaryKey, int expectCode = E_OK)
510     {
511         /**
512          * @tc.steps:step1. create table.
513          * @tc.expected: step1. return ok.
514          */
515         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
516         EXPECT_NE(db, nullptr);
517         EXPECT_EQ(RelationalTestUtils::ExecSql(db, createSql), E_OK);
518         SetCloudSchemaForCollate(ageIsPrimaryKey);
519 
520         /**
521          * @tc.steps:step2. create distributed table with CLOUD_COOPERATION mode.
522          * @tc.expected: step2. return ok.
523          */
524         EXPECT_EQ(g_delegate->CreateDistributedTable(g_tableName, DistributedDB::CLOUD_COOPERATION), OK);
525 
526         /**
527          * @tc.steps:step3. insert data in lower case.
528          * @tc.expected: step3. return ok.
529          */
530         EXPECT_EQ(RelationalTestUtils::ExecSql(db, insertSql), E_OK);
531         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
532 
533         /**
534          * @tc.steps:step4. construct cloud data in upper case, call GetInfoByPrimaryKeyOrGid
535          * @tc.expected: step4. return expectCode.
536          */
537         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
538         ASSERT_NE(storageProxy, nullptr);
539         EXPECT_EQ(storageProxy->StartTransaction(), E_OK);
540         VBucket vBucket;
541         std::string gid = g_gid + std::to_string(0);
542         vBucket["name"] = pkStr[0];
543         if (ageIsPrimaryKey) {
544             vBucket["age"] = pkStr[1];
545         }
546         vBucket[CloudDbConstant::GID_FIELD] = gid;
547         DataInfoWithLog dataInfoWithLog;
548         VBucket assetInfo;
549         EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), expectCode);
550         EXPECT_EQ(storageProxy->Commit(), E_OK);
551     }
552 
553     /**
554      * @tc.name: GetInfoByPrimaryKeyOrGidTest014
555      * @tc.desc: Test collate nocase for primary key(NOCASE followed by ','), case mismatch
556      * @tc.type: FUNC
557      * @tc.require:
558      * @tc.author: zhangshijie
559      */
560     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest014, TestSize.Level0)
561     {
562         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE NOCASE, age text);";
563         std::string insertSql = "insert into " + g_tableName + " values('abcd', '10');";
564         std::vector<std::string> pkStr = { "aBcD" };
565         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
566     }
567 
568     /**
569      * @tc.name: GetInfoByPrimaryKeyOrGidTest015
570      * @tc.desc: Test collate nocase for primary key, case match
571      * @tc.type: FUNC
572      * @tc.require:
573      * @tc.author: zhangshijie
574      */
575     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest015, TestSize.Level0)
576     {
577         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE NOCASE, age text);";
578         std::string insertSql = "insert into " + g_tableName + " values('abcd', '10');";
579         std::vector<std::string> pkStr = { "abcd" };
580         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
581     }
582 
583     /**
584      * @tc.name: GetInfoByPrimaryKeyOrGidTest016
585      * @tc.desc: Test collate nocase for primary key(NOCASE followed by ')'), case mismatch
586      * @tc.type: FUNC
587      * @tc.require:
588      * @tc.author: zhangshijie
589      */
590     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest016, TestSize.Level0)
591     {
592         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE NOCASE);";
593         std::string insertSql = "insert into " + g_tableName + " values('abcd');";
594         std::vector<std::string> pkStr = { "aBcD" };
595         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
596     }
597 
598     /**
599      * @tc.name: GetInfoByPrimaryKeyOrGidTest017
600      * @tc.desc: Test collate nocase for primary key(NOCASE followed by ' '), case mismatch
601      * @tc.type: FUNC
602      * @tc.require:
603      * @tc.author: zhangshijie
604      */
605     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest017, TestSize.Level0)
606     {
607         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE NOCASE , age int);";
608         std::string insertSql = "insert into " + g_tableName + " values('abcd', 10);";
609         std::vector<std::string> pkStr = { "aBcD" };
610         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
611     }
612 
613     /**
614      * @tc.name: GetInfoByPrimaryKeyOrGidTest018
615      * @tc.desc: Test collate nocase NOT for primary key, case mismatch
616      * @tc.type: FUNC
617      * @tc.require:
618      * @tc.author: zhangshijie
619      */
620     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest018, TestSize.Level0)
621     {
622         std::string createSql = "create table " + g_tableName + "(name text primary key, age TEXT COLLATE NOCASE);";
623         std::string insertSql = "insert into " + g_tableName + " values('abcd', '10');";
624         std::vector<std::string> pkStr = { "aBcD" };
625         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false, -E_NOT_FOUND);
626     }
627 
628     /**
629      * @tc.name: GetInfoByPrimaryKeyOrGidTest019
630      * @tc.desc: Test collate nocase for one primary key, one pk case mismatch
631      * @tc.type: FUNC
632      * @tc.require:
633      * @tc.author: zhangshijie
634      */
635     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest019, TestSize.Level0)
636     {
637         std::string createSql = "create table " + g_tableName + "(NAME text collate NOCASE, age text," +
638             "primary key(name, age));";
639         std::string insertSql = "insert into " + g_tableName + " values('abcd', 'ab');";
640         std::vector<std::string> pkStr = { "aBcD", "ab" };
641         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true);
642     }
643 
644     /**
645      * @tc.name: GetInfoByPrimaryKeyOrGidTest020
646      * @tc.desc: Test collate nocase for one primary key, two pk case mismatch
647      * @tc.type: FUNC
648      * @tc.require:
649      * @tc.author: zhangshijie
650      */
651     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest020, TestSize.Level0)
652     {
653         std::string createSql = "create table " + g_tableName + "(NAME text collate NOCASE, age text," +
654             "primary key(name, age));";
655         std::string insertSql = "insert into " + g_tableName + " values('abcd', 'aB');";
656         std::vector<std::string> pkStr = { "aBcD", "AB" };
657         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true, -E_NOT_FOUND);
658     }
659 
660     /**
661      * @tc.name: GetInfoByPrimaryKeyOrGidTest021
662      * @tc.desc: Test collate nocase for two primary key, two pk case mismatch
663      * @tc.type: FUNC
664      * @tc.require:
665      * @tc.author: zhangshijie
666      */
667     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest021, TestSize.Level0)
668     {
669         std::string createSql = "create table " + g_tableName + "(NAME text collate NOCASE, age text collate nocase," +
670             "primary key(name, age));";
671         std::string insertSql = "insert into " + g_tableName + " values('abcd', 'aB');";
672         std::vector<std::string> pkStr = { "aBcD", "ab" };
673         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true);
674     }
675 
676     /**
677     * @tc.name: GetInfoByPrimaryKeyOrGidTest022
678     * @tc.desc: Test collate rtrim for primary key(NOCASE followed by ','), trim mismatch
679     * @tc.type: FUNC
680     * @tc.require:
681     * @tc.author: zhangshijie
682     */
683     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest022, TestSize.Level0)
684     {
685         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE RTRIM, age text);";
686         std::string insertSql = "insert into " + g_tableName + " values('abcd ', '10');";
687         std::vector<std::string> pkStr = { "abcd" };
688         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
689     }
690 
691     /**
692      * @tc.name: GetInfoByPrimaryKeyOrGidTest023
693      * @tc.desc: Test collate nocase for primary key, trim match
694      * @tc.type: FUNC
695      * @tc.require:
696      * @tc.author: zhangshijie
697      */
698     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest023, TestSize.Level0)
699     {
700         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE RTRIM, age text);";
701         std::string insertSql = "insert into " + g_tableName + " values('abcd_', '10');";
702         std::vector<std::string> pkStr = { "abcd_" };
703         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
704     }
705 
706     /**
707      * @tc.name: GetInfoByPrimaryKeyOrGidTest024
708      * @tc.desc: Test collate rtrim for primary key(NOCASE followed by ')'), rtrim mismatch
709      * @tc.type: FUNC
710      * @tc.require:
711      * @tc.author: zhangshijie
712      */
713     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest024, TestSize.Level0)
714     {
715         std::string createSql = "create table " + g_tableName + "(name text primary key COLLATE rtrim);";
716         std::string insertSql = "insert into " + g_tableName + " values('abcd ');";
717         std::vector<std::string> pkStr = { "abcd" };
718         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false);
719     }
720 
721     /**
722      * @tc.name: GetInfoByPrimaryKeyOrGidTest025
723      * @tc.desc: Test collate rtrim NOT for primary key, rtrim mismatch
724      * @tc.type: FUNC
725      * @tc.require:
726      * @tc.author: zhangshijie
727      */
728     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest025, TestSize.Level0)
729     {
730         std::string createSql = "create table " + g_tableName + "(name text primary key, age TEXT COLLATE rtrim);";
731         std::string insertSql = "insert into " + g_tableName + " values('abcd ', '10');";
732         std::vector<std::string> pkStr = { "abcd" };
733         PrimaryKeyCollateTest(createSql, insertSql, pkStr, false, -E_NOT_FOUND);
734     }
735 
736     /**
737      * @tc.name: GetInfoByPrimaryKeyOrGidTest026
738      * @tc.desc: Test collate rtrim for one primary key, one pk rtrim mismatch
739      * @tc.type: FUNC
740      * @tc.require:
741      * @tc.author: zhangshijie
742      */
743     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest026, TestSize.Level0)
744     {
745         std::string createSql = "create table " + g_tableName + "(NAME text collate RTRIM, age text," +
746             "primary key(name, age));";
747         std::string insertSql = "insert into " + g_tableName + " values('abcd ', 'ab');";
748         std::vector<std::string> pkStr = { "abcd", "ab" };
749         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true);
750     }
751 
752     /**
753      * @tc.name: GetInfoByPrimaryKeyOrGidTest026
754      * @tc.desc: Test collate rtrim for one primary key, two pk rttim mismatch
755      * @tc.type: FUNC
756      * @tc.require:
757      * @tc.author: zhangshijie
758      */
759     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest027, TestSize.Level0)
760     {
761         std::string createSql = "create table " + g_tableName + "(NAME text collate rtrim, age text," +
762             "primary key(name, age));";
763         std::string insertSql = "insert into " + g_tableName + " values('abcd ', 'aB ');";
764         std::vector<std::string> pkStr = { "abcd", "aB" };
765         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true, -E_NOT_FOUND);
766     }
767 
768     /**
769      * @tc.name: GetInfoByPrimaryKeyOrGidTest027
770      * @tc.desc: Test collate rtrim for two primary key, two pk rtrim mismatch
771      * @tc.type: FUNC
772      * @tc.require:
773      * @tc.author: zhangshijie
774      */
775     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest028, TestSize.Level0)
776     {
777         std::string createSql = "create table " + g_tableName + "(NAME text collate rtrim, age text collate rtrim," +
778             "primary key(name, age));";
779         std::string insertSql = "insert into " + g_tableName + " values('abcd ', 'ab');";
780         std::vector<std::string> pkStr = { "abcd ", "ab " };
781         PrimaryKeyCollateTest(createSql, insertSql, pkStr, true);
782     }
783 
ConstructDownloadData(DownloadData & downloadData,GidType gidType,bool nullable,bool vBucketContains)784     void ConstructDownloadData(DownloadData &downloadData, GidType gidType, bool nullable, bool vBucketContains)
785     {
786         for (int i = 0; i < 7; i++) { // 7 is record counts
787             VBucket vBucket;
788             if (i == 3) { // 3 is record index
789                 vBucket["id"] = 4L + i; // id = 5, 6 already pre_insert
790             } else {
791                 vBucket["id"] = 1L + i;
792             }
793 
794             std::string name = "lisi" + std::to_string(i);
795             vBucket["name"] = name;
796             vBucket["age"] = 100.0 + i; // 100.0 is offset for cloud data
797             if (vBucketContains) {
798                 vBucket["sex"] = i % 2 ? true : false; // 2 is mod
799             }
800 
801             vBucket["image"] = std::vector<uint8_t>(1, i);
802             std::string gid;
803             if (gidType == GidType::GID_MATCH) {
804                 gid = g_gid + std::to_string(i);
805             } else if (gidType == GidType::GID_EMPTY) {
806                 std::string emptyGid = "";
807                 gid = emptyGid;
808             } else if (gidType == GidType::GID_INVALID) {
809                 std::string invalidGid = "abc'd";
810                 gid = invalidGid;
811             } else {
812                 gid = std::to_string(i) + g_gid;
813             }
814 
815             vBucket[CloudDbConstant::GID_FIELD] = gid;
816             int64_t cTime = 12345678L + i;
817             vBucket[CloudDbConstant::CREATE_FIELD] = cTime;
818             int64_t mTime = 12345679L + i;
819             vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
820             downloadData.data.push_back(vBucket);
821         }
822 
823         downloadData.opType = { OpType::UPDATE, OpType::DELETE, OpType::ONLY_UPDATE_GID, OpType::INSERT,
824             OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO, OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE, OpType::NOT_HANDLE };
825     }
826 
SaveCloudDataTest(PrimaryKeyType pkType,GidType gidType=GidType::GID_MATCH,bool nullable=true,bool vBucketContains=true,int expectCode=E_OK)827     void SaveCloudDataTest(PrimaryKeyType pkType, GidType gidType = GidType::GID_MATCH, bool nullable = true,
828         bool vBucketContains = true, int expectCode = E_OK)
829     {
830         /**
831          * @tc.steps:step1. create db, create table.
832          * @tc.expected: step1. return ok.
833          */
834         PrepareDataBase(g_tableName, pkType, nullable);
835 
836         /**
837          * @tc.steps:step2. call PutCloudSyncData
838          * @tc.expected: step2. return ok.
839          */
840         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
841         ASSERT_NE(storageProxy, nullptr);
842         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
843 
844         DownloadData downloadData;
845         ConstructDownloadData(downloadData, gidType, nullable, vBucketContains);
846         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), expectCode);
847         if (expectCode == E_OK) {
848             for (size_t i = 0; i < downloadData.opType.size(); i++) {
849                 if (downloadData.opType[i] == OpType::INSERT) {
850                     EXPECT_TRUE(downloadData.data[i].find(CloudDbConstant::ROW_ID_FIELD_NAME) !=
851                         downloadData.data[i].end());
852                 }
853             }
854         }
855         EXPECT_EQ(storageProxy->Commit(), E_OK);
856     }
857 
858     /**
859      * @tc.name: PutCloudSyncDataTest001
860      * @tc.desc: Test save cloud data into table with no primary key, gid match
861      * @tc.type: FUNC
862      * @tc.require:
863      * @tc.author: zhangshijie
864      */
865     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest001, TestSize.Level0)
866     {
867         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY);
868         // there is one log record with cloud_gid = abcd3(id = 7 will delete first, then insert again)
869         std::string sql = "select count(data_key) from " + DBCommon::GetLogTableName(g_tableName) +
870             " where cloud_gid = '" + g_gid + std::to_string(3) + "'"; // 3 is gid index
871         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
872         EXPECT_NE(db, nullptr);
__anon2ff534420202(sqlite3_stmt *stmt) 873         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [] (sqlite3_stmt *stmt) {
874             EXPECT_EQ(sqlite3_column_int64(stmt, 0), 1); // will get only 1 log record
875             return E_OK;
876         });
877         EXPECT_EQ(errCode, SQLITE_OK);
878         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
879     }
880 
881     /**
882      * @tc.name: PutCloudSyncDataTest002
883      * @tc.desc: Test save cloud data into table with no primary key, gid mismatch
884      * @tc.type: FUNC
885      * @tc.require:
886      * @tc.author: zhangshijie
887      */
888     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest002, TestSize.Level0)
889     {
890         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY, GidType::GID_MISMATCH);
891     }
892 
893     /**
894      * @tc.name: PutCloudSyncDataTest003
895      * @tc.desc: Test save cloud data into table with no primary key, gid is empty
896      * @tc.type: FUNC
897      * @tc.require:
898      * @tc.author: zhangshijie
899      */
900     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest003, TestSize.Level0)
901     {
902         SaveCloudDataTest(PrimaryKeyType::NO_PRIMARY_KEY, GidType::GID_EMPTY, true, true, -E_CLOUD_ERROR);
903     }
904 
905     /**
906      * @tc.name: PutCloudSyncDataTest004
907      * @tc.desc: Test save cloud data into table with single primary key, gid match
908      * @tc.type: FUNC
909      * @tc.require:
910      * @tc.author: zhangshijie
911      */
912     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest004, TestSize.Level0)
913     {
914         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
915     }
916 
917     /**
918      * @tc.name: PutCloudSyncDataTest005
919      * @tc.desc: Test save cloud data into table with single primary key, gid mismatch
920      * @tc.type: FUNC
921      * @tc.require:
922      * @tc.author: zhangshijie
923      */
924     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest005, TestSize.Level0)
925     {
926         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_MISMATCH);
927     }
928 
929     /**
930      * @tc.name: PutCloudSyncDataTest006
931      * @tc.desc: Test save cloud data into table with single primary key, gid is empty
932      * @tc.type: FUNC
933      * @tc.require:
934      * @tc.author: zhangshijie
935      */
936     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest006, TestSize.Level0)
937     {
938         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, true, true, -E_CLOUD_ERROR);
939     }
940 
941     /**
942      * @tc.name: PutCloudSyncDataTest007
943      * @tc.desc: Test save cloud data into table with single primary key, gid is empty, cloud field less than schema,
944      * field can be null
945      * @tc.type: FUNC
946      * @tc.require:
947      * @tc.author: zhangshijie
948      */
949     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest007, TestSize.Level0)
950     {
951         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_MATCH, true, false);
952     }
953 
954     /**
955      * @tc.name: PutCloudSyncDataTest008
956      * @tc.desc: Test save cloud data into table with single primary key, gid is empty, cloud field less than schema,
957      * field can not be null
958      * @tc.type: FUNC
959      * @tc.require:
960      * @tc.author: zhangshijie
961      */
962     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest008, TestSize.Level0)
963     {
964         SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, false, false, -E_CLOUD_ERROR);
965     }
966 
967     /**
968      * @tc.name: PutCloudSyncDataTest009
969      * @tc.desc: Test save cloud data into table with composite primary key, gid match, primary key mismatch
970      * @tc.type: FUNC
971      * @tc.require:
972      * @tc.author: zhangshijie
973      */
974     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest009, TestSize.Level0)
975     {
976         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
977     }
978 
979     /**
980      * @tc.name: PutCloudSyncDataTest010
981      * @tc.desc: Test save cloud data into table with composite primary key, gid mismatch, primary key mismatch
982      * @tc.type: FUNC
983      * @tc.require:
984      * @tc.author: zhangshijie
985      */
986     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest010, TestSize.Level0)
987     {
988         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, GidType::GID_MISMATCH);
989     }
990 
991     /**
992      * @tc.name: PutCloudSyncDataTest011
993      * @tc.desc: Test save cloud data into table with composite primary key, invalid gid
994      * @tc.type: FUNC
995      * @tc.require:
996      * @tc.author: zhangshijie
997      */
998     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest011, TestSize.Level0)
999     {
1000         SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, GidType::GID_INVALID, true, true, -E_CLOUD_ERROR);
1001     }
1002 
ConstructMultiDownloadData(DownloadData & downloadData,GidType gidType)1003     void ConstructMultiDownloadData(DownloadData &downloadData, GidType gidType)
1004     {
1005         for (int i = 0; i < 6; i++) { // 6 is record counts
1006             VBucket vBucket;
1007             if (i < 1) { // UPDATE_TIMESTAMP doesn't contain pk
1008                 vBucket["id"] = 1L + i;
1009             } else if (i > 1) {
1010                 vBucket["id"] = 10L + i; // 10 is id offset for cloud data
1011             }
1012 
1013             std::string name = "lisi" + std::to_string(i);
1014             vBucket["name"] = name;
1015             vBucket["age"] = 100.0 + i; // 100.0 is offset for cloud data
1016             vBucket["sex"] = i % 2 ? true : false; // 2 is mod
1017 
1018             vBucket["image"] = std::vector<uint8_t>(1, i);
1019             std::string gid;
1020             if (gidType == GidType::GID_MATCH) {
1021                 if (i <= 1) { // first 2 exists in local
1022                     gid = g_gid + std::to_string(i);
1023                 } else {
1024                     gid = g_gid + std::to_string(10 + i); // 10 is id offset for cloud data
1025                 }
1026             } else if (gidType == GidType::GID_EMPTY) {
1027                 std::string emptyGid = "";
1028                 gid = emptyGid;
1029             } else {
1030                 gid = std::to_string(i) + g_gid;
1031             }
1032 
1033             vBucket[CloudDbConstant::GID_FIELD] = gid;
1034             int64_t cTime = BASE_CREATE_TIME + i;
1035             vBucket[CloudDbConstant::CREATE_FIELD] = cTime;
1036             int64_t mTime = BASE_MODIFY_TIME + i;
1037             vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
1038             downloadData.data.push_back(vBucket);
1039         }
1040 
1041         downloadData.opType = { OpType::UPDATE, OpType::UPDATE_TIMESTAMP, OpType::INSERT, OpType::INSERT,
1042             OpType::INSERT, OpType::NOT_HANDLE };
1043     }
1044 
1045     /**
1046      * @tc.name: PutCloudSyncDataTest012
1047      * @tc.desc: Test save cloud data into table with no primary key, multi cloud data
1048      * @tc.type: FUNC
1049      * @tc.require:
1050      * @tc.author: zhangshijie
1051      */
1052     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest012, TestSize.Level0)
1053     {
1054         /**
1055          * @tc.steps:step1. create db, create table.
1056          * @tc.expected: step1. return ok.
1057          */
1058         PrepareDataBase(g_tableName, PrimaryKeyType::NO_PRIMARY_KEY, true);
1059 
1060         /**
1061          * @tc.steps:step2. call PutCloudSyncData
1062          * @tc.expected: step2. return ok.
1063          */
1064         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1065         ASSERT_NE(storageProxy, nullptr);
1066         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1067 
1068         DownloadData downloadData;
1069         ConstructMultiDownloadData(downloadData, GidType::GID_MATCH);
1070         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1071         EXPECT_EQ(storageProxy->Commit(), E_OK);
1072     }
1073 
1074     /**
1075      * @tc.name: PutCloudSyncDataTest013
1076      * @tc.desc: Test save cloud data with type = update_timestamp
1077      * @tc.type: FUNC
1078      * @tc.require:
1079      * @tc.author: zhangshijie
1080      */
1081     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest013, TestSize.Level0)
1082     {
1083         /**
1084          * @tc.steps:step1. create db, create table.
1085          * @tc.expected: step1. return ok.
1086          */
1087         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY, true);
1088 
1089         std::string sql = "delete from " + g_tableName + " where id = 2";
1090         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1091         EXPECT_NE(db, nullptr);
1092         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
1093         /**
1094          * @tc.steps:step2. call PutCloudSyncData
1095          * @tc.expected: step2. return ok.
1096          */
1097         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1098         ASSERT_NE(storageProxy, nullptr);
1099         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1100 
1101         DownloadData downloadData;
1102         ConstructMultiDownloadData(downloadData, GidType::GID_MATCH);
1103         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1104         EXPECT_EQ(storageProxy->Commit(), E_OK);
1105 
1106         /**
1107          * @tc.steps:step3. verify data
1108          * @tc.expected: step3. verify data ok.
1109          */
1110         sql = "select device, timestamp, flag from " + DBCommon::GetLogTableName(g_tableName) +
1111             " where data_key = -1 and cloud_gid = ''";
1112         int count = 0;
__anon2ff534420302(sqlite3_stmt *stmt) 1113         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1114             std::string device = "cloud";
1115             std::vector<uint8_t> deviceVec;
1116             (void)SQLiteUtils::GetColumnBlobValue(stmt, 0, deviceVec);    // 0 is device
1117             std::string getDevice;
1118             DBCommon::VectorToString(deviceVec, getDevice);
1119             EXPECT_EQ(device, getDevice);
1120             EXPECT_EQ(sqlite3_column_int64(stmt, 1), BASE_MODIFY_TIME + 1);
1121             EXPECT_EQ(sqlite3_column_int(stmt, 2), 0x20|0x01); // 2 is flag
1122             count++;
1123             return E_OK;
1124         });
1125         EXPECT_EQ(errCode, E_OK);
1126         EXPECT_EQ(count, 1);
1127         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
1128     }
1129 
1130     /**
1131      * @tc.name: PutCloudSyncDataTest014
1132      * @tc.desc: Test PutCloudSyncData when vbucket doesn't contain pk data and gid match,
1133      * @tc.type: FUNC
1134      * @tc.require:
1135      * @tc.author: zhangshijie
1136      */
1137     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest014, TestSize.Level0)
1138     {
1139         /**
1140          * @tc.steps:step1. create db, create table.
1141          * @tc.expected: step1. return ok.
1142          */
1143         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY);
1144 
1145         /**
1146          * @tc.steps:step2. construct data without primary key value, call PutCloudSyncData.
1147          * @tc.expected: step2. return E_OK.
1148          */
1149         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1150         ASSERT_NE(storageProxy, nullptr);
1151         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1152 
1153         DownloadData downloadData;
1154         VBucket vBucket;
1155         std::string gid = g_gid + std::to_string(0);
1156         vBucket[CloudDbConstant::GID_FIELD] = gid;
1157         vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
1158         downloadData.data.push_back(vBucket);
1159         downloadData.opType = { OpType::DELETE };
1160         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1161         EXPECT_EQ(storageProxy->Commit(), E_OK);
1162     }
1163 
1164     /**
1165      * @tc.name: PutCloudSyncDataTest015
1166      * @tc.desc: Test clear gid and ONLY_UPDATE_GID
1167      * @tc.type: FUNC
1168      * @tc.require:
1169      * @tc.author: zhangshijie
1170      */
1171     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest015, TestSize.Level0)
1172     {
1173         /**
1174          * @tc.steps:step1. create db, create table.
1175          * @tc.expected: step1. return ok.
1176          */
1177         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY);
1178 
1179         /**
1180          * @tc.steps:step2. construct data type = clear_gid, call PutCloudSyncData.
1181          * @tc.expected: step2. return E_OK.
1182          */
1183         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1184         ASSERT_NE(storageProxy, nullptr);
1185         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1186 
1187         DownloadData downloadData;
1188         for (int i = 0; i < 2; i++) { // 2 is record count
1189             VBucket vBucket;
1190             std::string gid = g_gid + std::to_string(i * 4); // 4 is data index
1191             vBucket[CloudDbConstant::GID_FIELD] = gid;
1192             vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
1193             downloadData.data.push_back(vBucket);
1194         }
1195         downloadData.opType = { OpType::ONLY_UPDATE_GID, OpType::CLEAR_GID };
1196         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1197         EXPECT_EQ(storageProxy->Commit(), E_OK);
1198 
1199         /**
1200          * @tc.steps:step3. verify data
1201          * @tc.expected: step3. verify data ok.
1202          */
1203         std::string sql = "select cloud_gid, flag from " + DBCommon::GetLogTableName(g_tableName) +
1204             " where data_key = 1 or data_key = 5";
1205         int count = 0;
1206         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1207         EXPECT_NE(db, nullptr);
__anon2ff534420402(sqlite3_stmt *stmt) 1208         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1209             std::string gid = "";
1210             if (count == 0) {
1211                 gid = g_gid + "0";
1212             }
1213             const unsigned char *val = sqlite3_column_text(stmt, 0);
1214             EXPECT_TRUE(val != nullptr);
1215             std::string getGid = reinterpret_cast<const char *>(val);
1216             LOGD("GET GID = %s", getGid.c_str());
1217             EXPECT_EQ(getGid, gid);
1218             if (count == 1) {
1219                 int flag = sqlite3_column_int(stmt, 1);
1220                 // 0x04 is binay num of b100, clear gid will clear 2th bit of flag
1221                 EXPECT_EQ(static_cast<uint16_t>(flag) & 0x04, 0);
1222             }
1223             count++;
1224             return E_OK;
1225         });
1226         EXPECT_EQ(errCode, E_OK);
1227         EXPECT_EQ(count, 2); // 2 is result count
1228         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
1229     }
1230 
DeleteWithPkTest(PrimaryKeyType pkType)1231     void DeleteWithPkTest(PrimaryKeyType pkType)
1232     {
1233         /**
1234          * @tc.steps:step1. create db, create table.
1235          * @tc.expected: step1. return ok.
1236          */
1237         PrepareDataBase(g_tableName, pkType, false);
1238 
1239         /**
1240          * @tc.steps:step2. call PutCloudSyncData
1241          * @tc.expected: step2. return ok.
1242          */
1243         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1244         ASSERT_NE(storageProxy, nullptr);
1245         EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1246 
1247         DownloadData downloadData;
1248         VBucket vBucket;
1249         vBucket["id"] = 1L;
1250         if (pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY) {
1251             std::string name = "zhangsan1";
1252             vBucket["name"] = name;
1253         }
1254 
1255         std::string gid = g_gid + "_not_exist"; // gid mismatch
1256         vBucket[CloudDbConstant::GID_FIELD] = gid;
1257         vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME;
1258         downloadData.data.push_back(vBucket);
1259         downloadData.opType = { OpType::DELETE };
1260         EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1261         EXPECT_EQ(storageProxy->Commit(), E_OK);
1262 
1263         /**
1264          * @tc.steps:step3. verify data
1265          * @tc.expected: step3. verify data ok.
1266          */
1267         std::string sql;
1268         if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) {
1269             sql = "select count(1) from " + g_tableName + " where id = 1";
1270         } else {
1271             sql = "select count(1) from " + g_tableName + " where id = 1 and name = 'zhangsan'";
1272         }
1273         int count = 0;
1274         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1275         EXPECT_NE(db, nullptr);
1276         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1277             EXPECT_EQ(sqlite3_column_int(stmt, 0), 0);
1278             count++;
1279             return E_OK;
1280         });
1281         EXPECT_EQ(errCode, E_OK);
1282         EXPECT_EQ(count, 1);
1283         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
1284     }
1285 
1286     /**
1287      * @tc.name: PutCloudSyncDataTest016
1288      * @tc.desc: Test delete data with pk in cloud data(normally there is no pk in cloud data when it is delete)
1289      * @tc.type: FUNC
1290      * @tc.require:
1291      * @tc.author: zhangshijie
1292      */
1293     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest016, TestSize.Level1)
1294     {
1295         DeleteWithPkTest(PrimaryKeyType::SINGLE_PRIMARY_KEY);
1296     }
1297 
1298     /**
1299      * @tc.name: PutCloudSyncDataTest017
1300      * @tc.desc: Test delete data with pk in cloud data(normally there is no pk in cloud data when it is delete)
1301      * primary key is COMPOSITE_PRIMARY_KEY
1302      * @tc.type: FUNC
1303      * @tc.require:
1304      * @tc.author: zhangshijie
1305      */
1306     HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest017, TestSize.Level1)
1307     {
1308         DeleteWithPkTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY);
1309     }
1310 
1311     /**
1312      * @tc.name: DropTableTest001
1313      * @tc.desc: Test drop table
1314      * @tc.type: FUNC
1315      * @tc.require:
1316      * @tc.author: zhangshijie
1317      */
1318     HWTEST_F(DistributedDBCloudSaveCloudDataTest, DropTableTest001, TestSize.Level1)
1319     {
1320         /**
1321          * @tc.steps:step1. create db, create table, prepare data.
1322          * @tc.expected: step1. ok.
1323          */
1324         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1325         EXPECT_NE(db, nullptr);
1326         EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
1327 
1328         std::string sql = "create table t_device(key int, value text);create table t_cloud(key int, value text);";
1329         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1330         EXPECT_EQ(g_delegate->CreateDistributedTable("t_device", DistributedDB::DEVICE_COOPERATION), OK);
1331         EXPECT_EQ(g_delegate->CreateDistributedTable("t_cloud", DistributedDB::CLOUD_COOPERATION), OK);
1332 
1333         sql = "insert into t_device values(1, 'zhangsan');insert into t_cloud values(1, 'zhangsan');";
1334         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1335         sql = "update " + DBCommon::GetLogTableName("t_cloud") + " set flag = 0";
1336         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1337 
1338         /**
1339          * @tc.steps:step2. drop table t_cloud, check log data
1340          * @tc.expected: step2. success.
1341          */
1342         sql = "drop table t_cloud;";
1343         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1344         sql = "select flag from " + DBCommon::GetLogTableName("t_cloud") + " where data_key = -1;";
1345         int count = 0;
__anon2ff534420602(sqlite3_stmt *stmt) 1346         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1347             EXPECT_EQ(sqlite3_column_int(stmt, 0), 3); // 3 mean local delete
1348             count++;
1349             return E_OK;
1350         });
1351         EXPECT_EQ(errCode, E_OK);
1352         EXPECT_EQ(count, 1);
1353 
1354         /**
1355          * @tc.steps:step3. drop table t_device, check log data
1356          * @tc.expected: step3. success.
1357          */
1358         sql = "drop table t_device;";
1359         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1360         sql = "select flag from " + DBCommon::GetLogTableName("t_device") + " where flag = 0x03;";
1361         count = 0;
__anon2ff534420702(sqlite3_stmt *stmt) 1362         errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) {
1363             count++;
1364             return E_OK;
1365         });
1366         EXPECT_EQ(errCode, E_OK);
1367         EXPECT_EQ(count, 1);
1368         EXPECT_EQ(sqlite3_close_v2(db), E_OK);
1369     }
1370 
1371     /**
1372      * @tc.name: GetDataWithAsset001
1373      * @tc.desc: Test get data with abnormal asset
1374      * @tc.type: FUNC
1375      * @tc.require:
1376      * @tc.author: zhangqiquan
1377      */
1378     HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetDataWithAsset001, TestSize.Level0)
1379     {
1380         /**
1381          * @tc.steps:step1. create db, create table, prepare data.
1382          * @tc.expected: step1. success.
1383          */
1384         PrepareDataBaseForAsset(g_assetTableName, true);
1385         RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
1386         std::shared_ptr<StorageProxy> storageProxy = GetStorageProxy(g_cloudStore);
1387         ASSERT_NE(storageProxy, nullptr);
1388         int errCode = storageProxy->StartTransaction();
1389         EXPECT_EQ(errCode, E_OK);
1390         /**
1391          * @tc.steps:step2. create db, create table, prepare data.
1392          * @tc.expected: step2. success.
1393          */
1394         ContinueToken token = nullptr;
1395         CloudSyncData data(g_assetTableName);
1396         errCode = storageProxy->GetCloudData(g_assetTableName, 0u, token, data);
1397         EXPECT_EQ(errCode, E_OK);
1398         EXPECT_EQ(data.ignoredCount, 1);
1399 
1400         EXPECT_EQ(storageProxy->Commit(), E_OK);
1401         EXPECT_EQ(token, nullptr);
1402         RuntimeConfig::SetCloudTranslate(nullptr);
1403     }
1404 
CheckCloudBatchData(CloudSyncBatch & batchData,bool existRef)1405     void CheckCloudBatchData(CloudSyncBatch &batchData, bool existRef)
1406     {
1407         for (size_t i = 0u; i < batchData.rowid.size(); ++i) {
1408             int64_t rowid = batchData.rowid[i];
1409             auto &extend = batchData.extend[i];
1410             ASSERT_EQ(extend.find(CloudDbConstant::REFERENCE_FIELD) != extend.end(), existRef);
1411             if (!existRef) {
1412                 continue;
1413             }
1414             Entries entries = std::get<Entries>(extend[CloudDbConstant::REFERENCE_FIELD]);
1415             EXPECT_EQ(std::to_string(rowid), entries["targetTable"]);
1416         }
1417     }
1418 
1419     /**
1420      * @tc.name: FillReferenceGid001
1421      * @tc.desc: Test fill gid data with normal
1422      * @tc.type: FUNC
1423      * @tc.require:
1424      * @tc.author: zhangqiquan
1425      */
1426     HWTEST_F(DistributedDBCloudSaveCloudDataTest, FillReferenceGid001, TestSize.Level0)
1427     {
1428         auto storage = new(std::nothrow) MockRelationalSyncAbleStorage();
1429         CloudSyncData syncData("FillReferenceGid001");
1430         EXPECT_CALL(*storage, GetReferenceGid).WillRepeatedly([&syncData](const std::string &tableName,
__anon2ff534420802(const std::string &tableName, const CloudSyncBatch &syncBatch, std::map<int64_t, Entries> &referenceGid) 1431             const CloudSyncBatch &syncBatch, std::map<int64_t, Entries> &referenceGid) {
1432             EXPECT_EQ(syncData.tableName, tableName);
1433             EXPECT_EQ(syncBatch.rowid.size(), 1u); // has 1 record
1434             for (auto rowid : syncBatch.rowid) {
1435                 Entries entries;
1436                 entries["targetTable"] = std::to_string(rowid);
1437                 referenceGid[rowid] = entries;
1438             }
1439             return E_OK;
1440         });
1441         syncData.insData.rowid.push_back(1); // rowid is 1
1442         syncData.insData.extend.resize(1);   // has 1 record
1443         syncData.updData.rowid.push_back(2); // rowid is 2
1444         syncData.updData.extend.resize(1);   // has 1 record
1445         syncData.delData.rowid.push_back(3); // rowid is 3
1446         syncData.delData.extend.resize(1);   // has 1 record
1447         EXPECT_EQ(storage->CallFillReferenceData(syncData), E_OK);
1448         CheckCloudBatchData(syncData.insData, true);
1449         CheckCloudBatchData(syncData.updData, true);
1450         CheckCloudBatchData(syncData.delData, false);
1451         RefObject::KillAndDecObjRef(storage);
1452     }
1453 
1454     /**
1455      * @tc.name: FillReferenceGid002
1456      * @tc.desc: Test fill gid data with abnormal
1457      * @tc.type: FUNC
1458      * @tc.require:
1459      * @tc.author: zhangqiquan
1460      */
1461     HWTEST_F(DistributedDBCloudSaveCloudDataTest, FillReferenceGid002, TestSize.Level0)
1462     {
1463         auto storage = new(std::nothrow) MockRelationalSyncAbleStorage();
1464         CloudSyncData syncData("FillReferenceGid002");
1465         syncData.insData.rowid.push_back(1); // rowid is 1
1466         EXPECT_CALL(*storage, GetReferenceGid).WillRepeatedly([](const std::string &,
__anon2ff534420902(const std::string &, const CloudSyncBatch &, std::map<int64_t, Entries> &referenceGid) 1467             const CloudSyncBatch &, std::map<int64_t, Entries> &referenceGid) {
1468             referenceGid[0] = {}; // create default
1469             return E_OK;
1470         });
1471         EXPECT_EQ(storage->CallFillReferenceData(syncData), -E_UNEXPECTED_DATA);
1472         syncData.insData.extend.resize(1); // rowid is 1
1473         EXPECT_EQ(storage->CallFillReferenceData(syncData), E_OK);
1474         RefObject::KillAndDecObjRef(storage);
1475     }
1476 
1477     /**
1478      * @tc.name: ConsistentFlagTest001
1479      * @tc.desc: Check the 0x20 bit of flag changed from the trigger
1480      * @tc.type: FUNC
1481      * @tc.require:
1482      * @tc.author: bty
1483      */
1484     HWTEST_F(DistributedDBCloudSaveCloudDataTest, ConsistentFlagTest001, TestSize.Level1)
1485     {
1486         /**
1487          * @tc.steps:step1. create db, create table, prepare data.
1488          * @tc.expected: step1. success.
1489          */
1490         PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY, true);
1491         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
1492         ASSERT_NE(db, nullptr);
1493         std::string sql = "insert into " + g_tableName + "(id, name) values(10, 'xx1'), (11, 'xx2')";
1494         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
1495         sql = "delete from " + g_tableName + "  where id=11;";
1496         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK);
1497 
1498         /**
1499          * @tc.steps:step2 query inserted and updated data, check flag
1500          * @tc.expected: step2. success.
1501          */
1502         sql = "select flag from " + DBCommon::GetLogTableName(g_tableName) +
1503             " where data_key in('10', '1')";
__anon2ff534420a02(sqlite3_stmt *stmt) 1504         int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [] (sqlite3_stmt *stmt) {
1505             EXPECT_EQ(sqlite3_column_int(stmt, 0), 0x20|0x02);
1506             return E_OK;
1507         });
1508         EXPECT_EQ(errCode, E_OK);
1509 
1510         /**
1511          * @tc.steps:step3 query deleted data which gid is not empty, check flag
1512          * @tc.expected: step3. success.
1513          */
1514         sql = "select flag from " + DBCommon::GetLogTableName(g_tableName) +
1515             " where data_key=-1 and cloud_gid !='';";
__anon2ff534420b02(sqlite3_stmt *stmt) 1516         errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [] (sqlite3_stmt *stmt) {
1517             EXPECT_EQ(sqlite3_column_int(stmt, 0), 0x20|0x03);
1518             return E_OK;
1519         });
1520         EXPECT_EQ(errCode, E_OK);
1521 
1522         /**
1523          * @tc.steps:step4 query deleted data which gid is empty, check flag
1524          * @tc.expected: step4. success.
1525          */
1526         sql = "select flag from " + DBCommon::GetLogTableName(g_tableName) +
1527               " where data_key=-1 and cloud_gid ='';";
__anon2ff534420c02(sqlite3_stmt *stmt) 1528         errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [] (sqlite3_stmt *stmt) {
1529             EXPECT_EQ(sqlite3_column_int(stmt, 0), 0x03);
1530             return E_OK;
1531         });
1532         EXPECT_EQ(errCode, E_OK);
1533         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
1534     }
1535 }
1536