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