• 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 #ifdef RELATIONAL_STORE
16 #include <gtest/gtest.h>
17 #include <iostream>
18 #include "cloud/cloud_storage_utils.h"
19 #include "cloud_db_constant.h"
20 #include "distributeddb_data_generate_unit_test.h"
21 #include "distributeddb_tools_unit_test.h"
22 #include "process_system_api_adapter_impl.h"
23 #include "relational_store_instance.h"
24 #include "relational_store_manager.h"
25 #include "runtime_config.h"
26 #include "sqlite_relational_store.h"
27 #include "sqlite_relational_utils.h"
28 #include "store_observer.h"
29 #include "time_helper.h"
30 #include "virtual_asset_loader.h"
31 #include "virtual_cloud_data_translate.h"
32 #include "virtual_cloud_db.h"
33 #include "mock_asset_loader.h"
34 
35 using namespace testing::ext;
36 using namespace DistributedDB;
37 using namespace DistributedDBUnitTest;
38 using namespace std;
39 
40 namespace {
41     string g_storeID = "Relational_Store_SYNC";
42     const string g_tableName1 = "worker1";
43     const string g_tableName2 = "worker2";
44     const string g_tableName3 = "worker3";
45     const string g_tableName4 = "worker4";
46     const string DEVICE_CLOUD = "cloud_dev";
47     const string DB_SUFFIX = ".db";
48     const int64_t g_syncWaitTime = 60;
49     const int g_arrayHalfSub = 2;
50     int g_syncIndex = 0;
51     string g_testDir;
52     string g_storePath;
53     std::mutex g_processMutex;
54     std::condition_variable g_processCondition;
55     std::shared_ptr<VirtualCloudDb> g_virtualCloudDb;
56     std::shared_ptr<VirtualAssetLoader> g_virtualAssetLoader;
57     DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
58     RelationalStoreObserverUnitTest *g_observer = nullptr;
59     RelationalStoreDelegate *g_delegate = nullptr;
60     SyncProcess g_syncProcess;
61     using CloudSyncStatusCallback = std::function<void(const std::map<std::string, SyncProcess> &onProcess)>;
62     const std::string CREATE_LOCAL_TABLE_SQL =
63             "CREATE TABLE IF NOT EXISTS " + g_tableName1 + "(" \
64     "name TEXT PRIMARY KEY," \
65     "height REAL ," \
66     "married BOOLEAN ," \
67     "photo BLOB NOT NULL," \
68     "assert BLOB," \
69     "age INT);";
70     const std::string INTEGER_PRIMARY_KEY_TABLE_SQL =
71             "CREATE TABLE IF NOT EXISTS " + g_tableName2 + "(" \
72     "id INTEGER PRIMARY KEY," \
73     "name TEXT ," \
74     "height REAL ," \
75     "photo BLOB ," \
76     "asserts BLOB," \
77     "age INT);";
78     const std::string DROP_INTEGER_PRIMARY_KEY_TABLE_SQL = "DROP TABLE " + g_tableName2 + ";";
79     const std::string CREATE_LOCAL_TABLE_WITHOUT_PRIMARY_KEY_SQL =
80             "CREATE TABLE IF NOT EXISTS " + g_tableName3 + "(" \
81     "name TEXT," \
82     "height REAL ," \
83     "married BOOLEAN ," \
84     "photo BLOB NOT NULL," \
85     "assert BLOB," \
86     "age INT);";
87     const std::string INTEGER_PRIMARY_KEY_TABLE_SQL_WRONG_SYNC_MODE =
88             "CREATE TABLE IF NOT EXISTS " + g_tableName4 + "(" \
89     "id INTEGER PRIMARY KEY," \
90     "name TEXT ," \
91     "height REAL ," \
92     "photo BLOB ," \
93     "asserts BLOB," \
94     "age INT);";
95     const std::vector<Field> g_cloudFiled1 = {
96         {"name", TYPE_INDEX<std::string>, true}, {"height", TYPE_INDEX<double>},
97         {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>, false, false},
98         {"assert", TYPE_INDEX<Asset>}, {"age", TYPE_INDEX<int64_t>}
99     };
100     const std::vector<Field> g_invalidCloudFiled1 = {
101         {"name", TYPE_INDEX<std::string>, true}, {"height", TYPE_INDEX<int>},
102         {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>, false, false},
103         {"assert", TYPE_INDEX<Bytes>}, {"age", TYPE_INDEX<int64_t>}
104     };
105     const std::vector<Field> g_cloudFiled2 = {
106         {"id", TYPE_INDEX<int64_t>, true}, {"name", TYPE_INDEX<std::string>},
107         {"height", TYPE_INDEX<double>},  {"photo", TYPE_INDEX<Bytes>},
108         {"asserts", TYPE_INDEX<Assets>}, {"age", TYPE_INDEX<int64_t>}
109     };
110     const std::vector<Field> g_cloudFiledWithOutPrimaryKey3 = {
111         {"name", TYPE_INDEX<std::string>, false, true}, {"height", TYPE_INDEX<double>},
112         {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>, false, false},
113         {"assert", TYPE_INDEX<Bytes>}, {"age", TYPE_INDEX<int64_t>}
114     };
115     const std::vector<std::string> g_tables = {g_tableName1, g_tableName2};
116     const std::vector<std::string> g_tablesPKey = {g_cloudFiled1[0].colName, g_cloudFiled2[0].colName};
117     const std::vector<string> g_prefix = {"Local", ""};
118     const Asset g_localAsset = {
119         .version = 1, .name = "Phone", .assetId = "0", .subpath = "/local/sync", .uri = "/local/sync",
120         .modifyTime = "123456", .createTime = "", .size = "256", .hash = "ASE"
121     };
122     const Asset g_cloudAsset = {
123         .version = 2, .name = "Phone", .assetId = "0", .subpath = "/local/sync", .uri = "/cloud/sync",
124         .modifyTime = "123456", .createTime = "0", .size = "1024", .hash = "DEC"
125     };
126 
CreateUserDBAndTable(sqlite3 * & db)127     void CreateUserDBAndTable(sqlite3 *&db)
128     {
129         EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
130         EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
131         EXPECT_EQ(RelationalTestUtils::ExecSql(db, INTEGER_PRIMARY_KEY_TABLE_SQL), SQLITE_OK);
132         EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_WITHOUT_PRIMARY_KEY_SQL), SQLITE_OK);
133     }
134 
InsertUserTableRecord(sqlite3 * & db,int64_t begin,int64_t count,int64_t photoSize,bool assetIsNull)135     void InsertUserTableRecord(sqlite3 *&db, int64_t begin, int64_t count, int64_t photoSize, bool assetIsNull)
136     {
137         std::string photo(photoSize, 'v');
138         int errCode;
139         std::vector<uint8_t> assetBlob;
140         for (int64_t i = begin; i < begin + count; ++i) {
141             Asset asset = g_localAsset;
142             asset.name = asset.name + std::to_string(i);
143             RuntimeContext::GetInstance()->AssetToBlob(asset, assetBlob);
144             string sql = "INSERT OR REPLACE INTO " + g_tableName1
145                          + " (name, height, married, photo, assert, age) VALUES ('Local" + std::to_string(i) +
146                          "', '175.8', '0', '" + photo + "', ? , '18');";
147             sqlite3_stmt *stmt = nullptr;
148             ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
149             if (assetIsNull) {
150                 ASSERT_EQ(sqlite3_bind_null(stmt, 1), SQLITE_OK);
151             } else {
152                 ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK);
153             }
154             EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
155             SQLiteUtils::ResetStatement(stmt, true, errCode);
156         }
157         for (int64_t i = begin; i < begin + count; ++i) {
158             std::vector<Asset> assets;
159             Asset asset = g_localAsset;
160             asset.name = g_localAsset.name + std::to_string(i);
161             assets.push_back(asset);
162             asset.name = g_localAsset.name + std::to_string(i + 1);
163             assets.push_back(asset);
164             RuntimeContext::GetInstance()->AssetsToBlob(assets, assetBlob);
165             string sql = "INSERT OR REPLACE INTO " + g_tableName2
166                          + " (id, name, height, photo, asserts, age) VALUES ('" + std::to_string(i) + "', 'Local"
167                          + std::to_string(i) + "', '155.10', '"+ photo + "',  ? , '21');";
168             sqlite3_stmt *stmt = nullptr;
169             ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
170             if (assetIsNull) {
171                 ASSERT_EQ(sqlite3_bind_null(stmt, 1), E_OK);
172             } else {
173                 ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK);
174             }
175             EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
176             SQLiteUtils::ResetStatement(stmt, true, errCode);
177         }
178         LOGD("insert user record worker1[primary key]:[Local%" PRId64 " - Local%" PRId64
179             ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count);
180     }
181 
InsertCloudTableRecord(int64_t begin,int64_t count,int64_t photoSize,bool assetIsNull)182     void InsertCloudTableRecord(int64_t begin, int64_t count, int64_t photoSize, bool assetIsNull)
183     {
184         std::vector<uint8_t> photo(photoSize, 'v');
185         std::vector<VBucket> record1;
186         std::vector<VBucket> extend1;
187         std::vector<VBucket> record2;
188         std::vector<VBucket> extend2;
189         Timestamp now = TimeHelper::GetSysCurrentTime();
190         for (int64_t i = begin; i < begin + count; ++i) {
191             VBucket data;
192             data.insert_or_assign("name", "Cloud" + std::to_string(i));
193             data.insert_or_assign("height", 166.0); // 166.0 is random double value
194             data.insert_or_assign("married", false);
195             data.insert_or_assign("photo", photo);
196             data.insert_or_assign("age", 13L);
197             Asset asset = g_cloudAsset;
198             asset.name = asset.name + std::to_string(i);
199             assetIsNull ? data.insert_or_assign("assert", Nil()) : data.insert_or_assign("assert", asset);
200             record1.push_back(data);
201             VBucket log;
202             log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i);
203             log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i);
204             log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false);
205             extend1.push_back(log);
206 
207             std::vector<Asset> assets;
208             data.insert_or_assign("id", i);
209             data.insert_or_assign("height", 180.3); // 180.3 is random double value
210             for (int64_t j = i; j <= i + 2; j++) { // 2 extra num
211                 asset.name = g_cloudAsset.name + std::to_string(j);
212                 assets.push_back(asset);
213             }
214             data.erase("assert");
215             data.erase("married");
216             assetIsNull ? data.insert_or_assign("asserts", Nil()) : data.insert_or_assign("asserts", assets);
217             record2.push_back(data);
218             extend2.push_back(log);
219         }
220         ASSERT_EQ(g_virtualCloudDb->BatchInsert(g_tableName1, std::move(record1), extend1), DBStatus::OK);
221         ASSERT_EQ(g_virtualCloudDb->BatchInsert(g_tableName2, std::move(record2), extend2), DBStatus::OK);
222         LOGD("insert cloud record worker1[primary key]:[cloud%" PRId64 " - cloud%" PRId64
223             ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count);
224         std::this_thread::sleep_for(std::chrono::milliseconds(count));
225     }
226 
GetCloudDbSchema(DataBaseSchema & dataBaseSchema)227     void GetCloudDbSchema(DataBaseSchema &dataBaseSchema)
228     {
229         TableSchema tableSchema1 = {
230             .name = g_tableName1,
231             .fields = g_cloudFiled1
232         };
233         TableSchema tableSchema2 = {
234             .name = g_tableName2,
235             .fields = g_cloudFiled2
236         };
237         TableSchema tableSchemaWithOutPrimaryKey = {
238             .name = g_tableName3,
239             .fields = g_cloudFiledWithOutPrimaryKey3
240         };
241         TableSchema tableSchema4 = {
242             .name = g_tableName4,
243             .fields = g_cloudFiled2
244         };
245         dataBaseSchema.tables.push_back(tableSchema1);
246         dataBaseSchema.tables.push_back(tableSchema2);
247         dataBaseSchema.tables.push_back(tableSchemaWithOutPrimaryKey);
248         dataBaseSchema.tables.push_back(tableSchema4);
249     }
250 
QueryCountCallback(void * data,int count,char ** colValue,char ** colName)251     int QueryCountCallback(void *data, int count, char **colValue, char **colName)
252     {
253         if (count != 1) {
254             return 0;
255         }
256         auto expectCount = reinterpret_cast<int64_t>(data);
257         EXPECT_EQ(strtol(colValue[0], nullptr, 10), expectCount); // 10: decimal
258         return 0;
259     }
260 
CheckCloudRecordNum(sqlite3 * & db,std::vector<std::string> tableList,std::vector<int> countList)261     void CheckCloudRecordNum(sqlite3 *&db, std::vector<std::string> tableList, std::vector<int> countList)
262     {
263         int i = 0;
264         for (const auto &tableName: tableList) {
265             std::string sql = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
266                 " where device = 'cloud'" + " and cloud_gid is not null and cloud_gid != '' and flag & 0x2 = 0;";
267             EXPECT_EQ(sqlite3_exec(db, sql.c_str(), QueryCountCallback,
268                 reinterpret_cast<void *>(countList[i]), nullptr), SQLITE_OK);
269             i++;
270         }
271     }
272 
CheckCleanLogNum(sqlite3 * & db,const std::vector<std::string> tableList,int count)273     void CheckCleanLogNum(sqlite3 *&db, const std::vector<std::string> tableList, int count)
274     {
275         for (const auto &tableName: tableList) {
276             std::string sql1 = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
277                 " where device = 'cloud';";
278             EXPECT_EQ(sqlite3_exec(db, sql1.c_str(), QueryCountCallback,
279                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
280             std::string sql2 = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
281                 " where cloud_gid " + " is not null and cloud_gid != '';";
282             EXPECT_EQ(sqlite3_exec(db, sql2.c_str(), QueryCountCallback,
283                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
284             std::string sql3 = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
285                 " where flag & 0x02 = 0;";
286             EXPECT_EQ(sqlite3_exec(db, sql3.c_str(), QueryCountCallback,
287                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
288         }
289     }
290 
CheckCleanDataAndLogNum(sqlite3 * & db,const std::vector<std::string> tableList,int count,std::vector<int> localNum)291     void CheckCleanDataAndLogNum(sqlite3 *&db, const std::vector<std::string> tableList, int count,
292         std::vector<int> localNum)
293     {
294         int i = 0;
295         for (const auto &tableName: tableList) {
296             std::string sql1 = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
297                 " where device = 'cloud';";
298             EXPECT_EQ(sqlite3_exec(db, sql1.c_str(), QueryCountCallback,
299                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
300             std::string sql2 = "select count(*) from " + DBCommon::GetLogTableName(tableName) + " where cloud_gid "
301                 " is not null and cloud_gid != '';";
302             EXPECT_EQ(sqlite3_exec(db, sql2.c_str(), QueryCountCallback,
303                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
304             std::string sql3 = "select count(*) from " + DBCommon::GetLogTableName(tableName) +
305                 " where flag & 0x02 = 0;";
306             EXPECT_EQ(sqlite3_exec(db, sql3.c_str(), QueryCountCallback,
307                 reinterpret_cast<void *>(count), nullptr), SQLITE_OK);
308             std::string local_sql = "select count(*) from " + tableName +";";
309             EXPECT_EQ(sqlite3_exec(db, local_sql.c_str(), QueryCountCallback,
310                 reinterpret_cast<void *>(localNum[i]), nullptr), SQLITE_OK);
311             i++;
312         }
313     }
314 
InitProcessForCleanCloudData1(const uint32_t & cloudCount,std::vector<SyncProcess> & expectProcess)315     void InitProcessForCleanCloudData1(const uint32_t &cloudCount, std::vector<SyncProcess> &expectProcess)
316     {
317         // cloudCount also means data count in one batch
318         expectProcess.clear();
319         std::vector<TableProcessInfo> infos;
320         uint32_t index = 1;
321         infos.push_back(TableProcessInfo{
322             FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0}
323         });
324         infos.push_back(TableProcessInfo{
325             PREPARED, {0, 0, 0, 0}, {0, 0, 0, 0}
326         });
327 
328         infos.push_back(TableProcessInfo{
329             FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0}
330         });
331         infos.push_back(TableProcessInfo{
332             FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0}
333         });
334 
335         for (size_t i = 0; i < infos.size() / g_arrayHalfSub; ++i) {
336             SyncProcess syncProcess;
337             syncProcess.errCode = OK;
338             syncProcess.process = i == infos.size() ? FINISHED : PROCESSING;
339             syncProcess.tableProcess.insert_or_assign(g_tables[0], std::move(infos[g_arrayHalfSub * i]));
340             syncProcess.tableProcess.insert_or_assign(g_tables[1], std::move(infos[g_arrayHalfSub * i + 1]));
341             expectProcess.push_back(syncProcess);
342         }
343     }
344 
GetCallback(SyncProcess & syncProcess,CloudSyncStatusCallback & callback,std::vector<SyncProcess> & expectProcess)345     void GetCallback(SyncProcess &syncProcess, CloudSyncStatusCallback &callback,
346         std::vector<SyncProcess> &expectProcess)
347     {
348         g_syncIndex = 0;
349         callback = [&syncProcess, &expectProcess](const std::map<std::string, SyncProcess> &process) {
350             LOGI("devices size = %d", process.size());
351             ASSERT_EQ(process.size(), 1u);
352             syncProcess = std::move(process.begin()->second);
353             ASSERT_EQ(process.begin()->first, DEVICE_CLOUD);
354             ASSERT_NE(syncProcess.tableProcess.empty(), true);
355             LOGI("current sync process status:%d, db status:%d ", syncProcess.process, syncProcess.errCode);
356             std::for_each(g_tables.begin(), g_tables.end(), [&](const auto &item) {
357                 auto table1 = syncProcess.tableProcess.find(item);
358                 if (table1 != syncProcess.tableProcess.end()) {
359                     LOGI("table[%s], table process status:%d, [downloadInfo](batchIndex:%u, total:%u, successCount:%u, "
360                          "failCount:%u) [uploadInfo](batchIndex:%u, total:%u, successCount:%u,failCount:%u",
361                          item.c_str(), table1->second.process, table1->second.downLoadInfo.batchIndex,
362                          table1->second.downLoadInfo.total, table1->second.downLoadInfo.successCount,
363                          table1->second.downLoadInfo.failCount, table1->second.upLoadInfo.batchIndex,
364                          table1->second.upLoadInfo.total, table1->second.upLoadInfo.successCount,
365                          table1->second.upLoadInfo.failCount);
366                 }
367             });
368             if (expectProcess.empty()) {
369                 if (syncProcess.process == FINISHED) {
370                     g_processCondition.notify_one();
371                 }
372                 return;
373             }
374             ASSERT_LE(static_cast<size_t>(g_syncIndex), expectProcess.size());
375             for (size_t i = 0; i < g_tables.size(); ++i) {
376                 SyncProcess head = expectProcess[g_syncIndex];
377                 for (auto &expect : head.tableProcess) {
378                     auto real = syncProcess.tableProcess.find(expect.first);
379                     ASSERT_NE(real, syncProcess.tableProcess.end());
380                     EXPECT_EQ(expect.second.process, real->second.process);
381                     EXPECT_EQ(expect.second.downLoadInfo.batchIndex, real->second.downLoadInfo.batchIndex);
382                     EXPECT_EQ(expect.second.downLoadInfo.total, real->second.downLoadInfo.total);
383                     EXPECT_EQ(expect.second.downLoadInfo.successCount, real->second.downLoadInfo.successCount);
384                     EXPECT_EQ(expect.second.downLoadInfo.failCount, real->second.downLoadInfo.failCount);
385                     EXPECT_EQ(expect.second.upLoadInfo.batchIndex, real->second.upLoadInfo.batchIndex);
386                     EXPECT_EQ(expect.second.upLoadInfo.total, real->second.upLoadInfo.total);
387                     EXPECT_EQ(expect.second.upLoadInfo.successCount, real->second.upLoadInfo.successCount);
388                     EXPECT_EQ(expect.second.upLoadInfo.failCount, real->second.upLoadInfo.failCount);
389                 }
390             }
391             g_syncIndex++;
392             if (syncProcess.process == FINISHED) {
393                 g_processCondition.notify_one();
394             }
395         };
396     }
397 
WaitForSyncFinish(SyncProcess & syncProcess,const int64_t & waitTime)398     void WaitForSyncFinish(SyncProcess &syncProcess, const int64_t &waitTime)
399     {
400         std::unique_lock<std::mutex> lock(g_processMutex);
401         bool result = g_processCondition.wait_for(lock, std::chrono::seconds(waitTime), [&syncProcess]() {
402             return syncProcess.process == FINISHED;
403         });
404         ASSERT_EQ(result, true);
405         LOGD("-------------------sync end--------------");
406     }
407 
CloseDb()408     void CloseDb()
409     {
410         delete g_observer;
411         g_virtualCloudDb = nullptr;
412         if (g_delegate != nullptr) {
413             EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK);
414             g_delegate = nullptr;
415         }
416     }
417 
418     class DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest : public testing::Test {
419     public:
420         static void SetUpTestCase(void);
421         static void TearDownTestCase(void);
422         void SetUp();
423         void TearDown();
424     protected:
425         sqlite3 *db = nullptr;
426     };
427 
SetUpTestCase(void)428     void DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest::SetUpTestCase(void)
429     {
430         DistributedDBToolsUnitTest::TestDirInit(g_testDir);
431         g_storePath = g_testDir + "/" + g_storeID + DB_SUFFIX;
432         LOGI("The test db is:%s", g_testDir.c_str());
433         RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
434     }
435 
TearDownTestCase(void)436     void DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest::TearDownTestCase(void)
437     {}
438 
SetUp(void)439     void DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest::SetUp(void)
440     {
441         if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
442             LOGE("rm test db files error.");
443         }
444         DistributedDBToolsUnitTest::PrintTestCaseInfo();
445         LOGD("Test dir is %s", g_testDir.c_str());
446         db = RelationalTestUtils::CreateDataBase(g_storePath);
447         ASSERT_NE(db, nullptr);
448         CreateUserDBAndTable(db);
449         g_observer = new (std::nothrow) RelationalStoreObserverUnitTest();
450         ASSERT_NE(g_observer, nullptr);
451         ASSERT_EQ(g_mgr.OpenStore(g_storePath, g_storeID, RelationalStoreDelegate::Option { .observer = g_observer },
452             g_delegate), DBStatus::OK);
453         ASSERT_NE(g_delegate, nullptr);
454         ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName1, CLOUD_COOPERATION), DBStatus::OK);
455         ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName2, CLOUD_COOPERATION), DBStatus::OK);
456         ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName3, CLOUD_COOPERATION), DBStatus::OK);
457         g_virtualCloudDb = make_shared<VirtualCloudDb>();
458         g_virtualAssetLoader = make_shared<VirtualAssetLoader>();
459         g_syncProcess = {};
460         ASSERT_EQ(g_delegate->SetCloudDB(g_virtualCloudDb), DBStatus::OK);
461         ASSERT_EQ(g_delegate->SetIAssetLoader(g_virtualAssetLoader), DBStatus::OK);
462         // sync before setting cloud db schema,it should return SCHEMA_MISMATCH
463         Query query = Query::Select().FromTable(g_tables);
464         CloudSyncStatusCallback callback;
465         ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime),
466             DBStatus::SCHEMA_MISMATCH);
467         DataBaseSchema dataBaseSchema;
468         GetCloudDbSchema(dataBaseSchema);
469         ASSERT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK);
470     }
471 
TearDown(void)472     void DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest::TearDown(void)
473     {
474         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
475         if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
476             LOGE("rm test db files error.");
477         }
478     }
479 
480 /*
481  * @tc.name: CleanCloudDataTest001
482  * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData, and invalid mode else.
483  * @tc.type: FUNC
484  * @tc.require:
485  * @tc.author: huangboxin
486  */
487 HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest001, TestSize.Level0)
488 {
489     int64_t paddingSize = 10;
490     int localCount = 10;
491     int cloudCount = 20;
492     InsertCloudTableRecord(0, cloudCount, paddingSize, false);
493     InsertUserTableRecord(db, 0, localCount, paddingSize, false);
494     Query query = Query::Select().FromTable(g_tables);
495     std::vector<SyncProcess> expectProcess;
496     InitProcessForCleanCloudData1(cloudCount, expectProcess);
497     CloudSyncStatusCallback callback;
498     GetCallback(g_syncProcess, callback, expectProcess);
499     ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime),
500         DBStatus::OK);
501     WaitForSyncFinish(g_syncProcess, g_syncWaitTime);
502     std::string device = "";
503     CheckCloudRecordNum(db, g_tables, {20, 20});
504     ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_ONLY), DBStatus::OK);
505     CheckCleanLogNum(db, g_tables, 0);
506 
507     ASSERT_EQ(g_delegate->RemoveDeviceData(device, ClearMode(BUTT + 1)), DBStatus::INVALID_ARGS);
508     ASSERT_EQ(g_delegate->RemoveDeviceData(device, ClearMode(-1)), DBStatus::INVALID_ARGS);
509 
510     CloseDb();
511 }
512 
513 /*
514  * @tc.name: CleanCloudDataTest002
515  * @tc.desc: Test FLAG_AND_DATA mode of RemoveDeviceData
516  * @tc.type: FUNC
517  * @tc.require:
518  * @tc.author: huangboxin
519  */
520 HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest002, TestSize.Level0)
521 {
522     int64_t paddingSize = 10;
523     int localCount = 10;
524     int cloudCount = 20;
525     InsertCloudTableRecord(0, cloudCount, paddingSize, false);
526     InsertUserTableRecord(db, 0, localCount, paddingSize, false);
527     Query query = Query::Select().FromTable(g_tables);
528     std::vector<SyncProcess> expectProcess;
529     InitProcessForCleanCloudData1(cloudCount, expectProcess);
530     CloudSyncStatusCallback callback;
531     GetCallback(g_syncProcess, callback, expectProcess);
532     ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime),
533         DBStatus::OK);
534     WaitForSyncFinish(g_syncProcess, g_syncWaitTime);
535     std::string device = "";
536     CheckCloudRecordNum(db, g_tables, {20, 20});    // 20 means cloud data num
537     ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK);
538     CheckCleanDataAndLogNum(db, g_tables, 0, {localCount, 0});
539     CloseDb();
540 }
541 
542 /*
543  * @tc.name: CleanCloudDataTest003
544  * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData concurrently with Sync
545  * @tc.type: FUNC
546  * @tc.require:
547  * @tc.author: huangboxin
548  */
549 HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest003, TestSize.Level0)
550 {
551     /**
552      * @tc.steps: step1. make data: 10 records on local and 20 records on cloud
553      */
554     int64_t paddingSize = 10;
555     int localCount = 10;
556     int cloudCount = 20;
557     InsertCloudTableRecord(0, cloudCount, paddingSize, false);
558     InsertUserTableRecord(db, 0, localCount, paddingSize, false);
559     /**
560      * @tc.steps: step2. call Sync with cloud force pull strategy, and after that, local will has 20 records.
561      */
562     Query query = Query::Select().FromTable(g_tables);
563     std::vector<SyncProcess> expectProcess;
564     InitProcessForCleanCloudData1(cloudCount, expectProcess);
565     CloudSyncStatusCallback callback;
566     GetCallback(g_syncProcess, callback, expectProcess);
567     ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime),
568         DBStatus::OK);
569     WaitForSyncFinish(g_syncProcess, g_syncWaitTime);
570     CheckCloudRecordNum(db, g_tables, {20, 20});    // 20 means cloud data num
571 
572     /**
573      * @tc.steps: step3. insert 10 records into local, so local will has 20 local records and 20 cloud records.
574      */
575     InsertUserTableRecord(db, 21, localCount, paddingSize, false);  // 21 means insert start index
576     /**
577      * @tc.steps: step4. call RemoveDeviceData synchronize with Sync with cloud force push strategy.
578      */
579     g_syncProcess = {};
580     std::vector<SyncProcess> expectProcess2;
581     InitProcessForCleanCloudData1(cloudCount, expectProcess2);
582     CloudSyncStatusCallback callback2;
583     GetCallback(g_syncProcess, callback2, expectProcess2);
584     std::string device = "";
585 
__anon93bd12370502() 586     std::thread thread1([&]() {
587         ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK);
588     });
__anon93bd12370602() 589     std::thread thread2([&]() {
590         ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback2, g_syncWaitTime),
591             DBStatus::OK);
592         LOGD("-------------------sync end--------------");
593     });
594     thread1.join();
595     thread2.join();
596     WaitForSyncFinish(g_syncProcess, g_syncWaitTime);
597     CheckCleanLogNum(db, g_tables, 20);
598     LOGD("================================== test clean cloud data 003 end ===================================");
599     CloseDb();
600 }
601 
InitGetCloudSyncTaskCountTest001(sqlite3 * & db)602 static void InitGetCloudSyncTaskCountTest001(sqlite3 *&db)
603 {
604     int64_t localCount = 20;
605     int64_t cloudCount = 10;
606     int64_t paddingSize = 100;
607     InsertUserTableRecord(db, 0, localCount, paddingSize, false);
608     InsertCloudTableRecord(0, cloudCount, paddingSize, false);
609 }
610 /*
611  * @tc.name: GetCloudSyncTaskCountTest001
612  * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData concurrently with Sync
613  * @tc.type: FUNC
614  * @tc.require:
615  * @tc.author: huangboxin
616  */
617 HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, GetCloudSyncTaskCountTest001, TestSize.Level0)
618 {
619     InitGetCloudSyncTaskCountTest001(db);
620     Query query = Query::Select().FromTable(g_tables);
621     std::mutex dataMutex1, dataMutex2;
622     std::condition_variable cv1, cv2;
623     bool finish1 = false, finish2 = false;
624     /**
625      * @tc.steps: step1. Call Sync once.
626      * @tc.expected: OK.
627      */
628     CloudSyncStatusCallback callback1 = [&dataMutex1, &cv1, &finish1](
__anon93bd12370702( const std::map<std::string, SyncProcess> &process) 629         const std::map<std::string, SyncProcess> &process) {
630         std::map<std::string, SyncProcess> syncProcess;
631         {
632             std::lock_guard<std::mutex> autoLock(dataMutex1);
633             syncProcess = process;
634             if (syncProcess[DEVICE_CLOUD].process == FINISHED) {
635                 finish1 = true;
636             }
637         }
638         cv1.notify_one();
639     };
640     /**
641      * @tc.steps: step2. Call Sync twice.
642      * @tc.expected: OK.
643      */
644     ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback1, g_syncWaitTime), DBStatus::OK);
645 
646     CloudSyncStatusCallback callback2 = [&dataMutex2, &cv2, &finish2](
__anon93bd12370802( const std::map<std::string, SyncProcess> &process) 647         const std::map<std::string, SyncProcess> &process) {
648         std::map<std::string, SyncProcess> syncProcess;
649         {
650             std::lock_guard<std::mutex> autoLock(dataMutex2);
651             syncProcess = process;
652             if (syncProcess[DEVICE_CLOUD].process == FINISHED) {
653                 finish2 = true;
654             }
655         }
656         cv2.notify_one();
657     };
658     ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback2, g_syncWaitTime), DBStatus::OK);
659     /**
660      * @tc.steps: step3. Call Get Cloud Sync Task Count
661      * @tc.expected: OK.
662      */
663     EXPECT_EQ(g_delegate->GetCloudSyncTaskCount(), 2);  // 2 is task count
664     /**
665      * @tc.steps: step3. Wait For Sync Task Finished
666      * @tc.expected: OK.
667      */
668     {
669         std::unique_lock<std::mutex> uniqueLock(dataMutex1);
__anon93bd12370902null670         cv1.wait(uniqueLock, [&finish1] {
671             return finish1;
672         });
673     }
674     {
675         std::unique_lock<std::mutex> uniqueLock(dataMutex2);
__anon93bd12370a02null676         cv2.wait(uniqueLock, [&finish2] {
677             return finish2;
678         });
679     }
680     CloseDb();
681 }
682 
683 /*
684  * @tc.name: CleanCloudDataTest004
685  * @tc.desc: Test  RemoveDeviceData when cloudSchema doesn't have local table
686  * @tc.type: FUNC
687  * @tc.require:
688  * @tc.author: huangboxin
689  */
690 HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest004, TestSize.Level0)
691 {
692     DataBaseSchema dataBaseSchema;
693     TableSchema tableSchema1 = {
694         .name = "table_not_existed",
695         .fields = g_cloudFiled1
696     };
697     dataBaseSchema.tables.push_back(tableSchema1);
698     GetCloudDbSchema(dataBaseSchema);
699     ASSERT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK);
700     std::string device = "";
701     ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK);
702     CloseDb();
703 }
704 
705 }
706 #endif // RELATIONAL_STORE