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/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 "virtual_communicator_aggregator.h"
34 #include "mock_asset_loader.h"
35 #include "cloud_db_sync_utils_test.h"
36 
37 using namespace testing::ext;
38 using namespace DistributedDB;
39 using namespace DistributedDBUnitTest;
40 using namespace std;
41 
42 namespace {
43     string g_storeID = "Relational_Store_SYNC";
44     const string g_tableName = "worker";
45     const string DB_SUFFIX = ".db";
46     const string CLOUD = "cloud";
47     string g_testDir;
48     string g_storePath;
49     std::shared_ptr<VirtualCloudDb> g_virtualCloudDb;
50     std::shared_ptr<VirtualAssetLoader> g_virtualAssetLoader;
51     RelationalStoreObserverUnitTest *g_observer = nullptr;
52     RelationalStoreDelegate *g_delegate = nullptr;
53     const std::vector<std::string> g_tables = {g_tableName};
54     const std::string CREATE_LOCAL_TABLE_COMPOUND_PRIMARY_KEY_SQL =
55         "CREATE TABLE IF NOT EXISTS " + g_tableName + "(" \
56         "name TEXT," \
57         "height REAL ," \
58         "married BOOLEAN ," \
59         "photo BLOB NOT NULL," \
60         "asset BLOB," \
61         "age INT," \
62         "PRIMARY KEY (" \
63         "  name," \
64         "  age)" \
65         ");";
66     const std::vector<Field> g_cloudFiledCompoundPrimaryKey = {
67         {"name", TYPE_INDEX<std::string>, true}, {"height", TYPE_INDEX<double>},
68         {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>, false, false},
69         {"asset", TYPE_INDEX<Asset>}, {"age", TYPE_INDEX<int64_t>, true}
70     };
71 
InitExpectChangedData(ChangedDataType dataType,int64_t count,ChangeType changeType)72     void InitExpectChangedData(ChangedDataType dataType, int64_t count, ChangeType changeType)
73     {
74         ChangedData changedDataForTable;
75         changedDataForTable.tableName = g_tableName;
76         changedDataForTable.type = dataType;
77         changedDataForTable.field.push_back(std::string("rowid"));
78         changedDataForTable.field.push_back(std::string("name"));
79         changedDataForTable.field.push_back(std::string("age"));
80         for (int64_t i = 0; i < count; ++i) {
81             changedDataForTable.primaryData[changeType].push_back({i + 1,
82                 "Cloud" + to_string(i), 13L}); // 13 is expect age
83         }
84         g_observer->SetExpectedResult(changedDataForTable);
85     }
86 
87     class DistributedDBCloudTableCompoundPrimaryKeySyncTest : public testing::Test {
88     public:
89         static void SetUpTestCase(void);
90         static void TearDownTestCase(void);
91         void SetUp();
92         void TearDown();
93     protected:
94         sqlite3 *db = nullptr;
95         VirtualCommunicatorAggregator *communicatorAggregator_ = nullptr;
96     };
97 
SetUpTestCase(void)98     void DistributedDBCloudTableCompoundPrimaryKeySyncTest::SetUpTestCase(void)
99     {
100         DistributedDBToolsUnitTest::TestDirInit(g_testDir);
101         g_storePath = g_testDir + "/" + g_storeID + DB_SUFFIX;
102         LOGI("The test db is:%s", g_testDir.c_str());
103         RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
104     }
105 
TearDownTestCase(void)106     void DistributedDBCloudTableCompoundPrimaryKeySyncTest::TearDownTestCase(void)
107     {}
108 
SetUp(void)109     void DistributedDBCloudTableCompoundPrimaryKeySyncTest::SetUp(void)
110     {
111         if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
112             LOGE("rm test db files error.");
113         }
114         DistributedDBToolsUnitTest::PrintTestCaseInfo();
115         LOGD("Test dir is %s", g_testDir.c_str());
116         db = RelationalTestUtils::CreateDataBase(g_storePath);
117         ASSERT_NE(db, nullptr);
118         CloudDBSyncUtilsTest::CreateUserDBAndTable(db, CREATE_LOCAL_TABLE_COMPOUND_PRIMARY_KEY_SQL);
119         CloudDBSyncUtilsTest::SetStorePath(g_storePath);
120         CloudDBSyncUtilsTest::InitSyncUtils(g_cloudFiledCompoundPrimaryKey, g_observer, g_virtualCloudDb,
121             g_virtualAssetLoader, g_delegate);
122         communicatorAggregator_ = new (std::nothrow) VirtualCommunicatorAggregator();
123         ASSERT_TRUE(communicatorAggregator_ != nullptr);
124         RuntimeContext::GetInstance()->SetCommunicatorAggregator(communicatorAggregator_);
125     }
126 
TearDown(void)127     void DistributedDBCloudTableCompoundPrimaryKeySyncTest::TearDown(void)
128     {
129         CloudDBSyncUtilsTest::CloseDb(g_observer, g_virtualCloudDb, g_delegate);
130         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
131         if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
132             LOGE("rm test db files error.");
133         }
134         RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr);
135         communicatorAggregator_ = nullptr;
136         RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(nullptr);
137     }
138 
139 /*
140  * @tc.name: CloudSyncTest001
141  * @tc.desc: test data sync when cloud insert
142  * @tc.type: FUNC
143  * @tc.require:
144  * @tc.author: chenchaohao
145  */
146 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest001, TestSize.Level0)
147 {
148     /**
149      * @tc.steps:step1. insert cloud data and merge
150      * @tc.expected: step1. check the changeddata and return ok
151      */
152     int64_t cloudCount = 10; // 10 is random cloud count
153     int64_t paddingSize = 10; // 10 is padding size
154     InitExpectChangedData(ChangedDataType::DATA, cloudCount, ChangeType::OP_INSERT);
155     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, true, g_virtualCloudDb);
156     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
157     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
158     g_observer->ClearChangedData();
159     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
160     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
161 }
162 
163 /*
164  * @tc.name: CloudSyncTest002
165  * @tc.desc: test data sync when cloud update
166  * @tc.type: FUNC
167  * @tc.require:
168  * @tc.author: chenchaohao
169  */
170 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest002, TestSize.Level0)
171 {
172     /**
173      * @tc.steps:step1. insert cloud data and merge
174      * @tc.expected: step1. check the changeddata and return ok
175      */
176     int64_t cloudCount = 10; // 10 is random cloud count
177     int64_t paddingSize = 10; // 10 is padding size
178     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, true, g_virtualCloudDb);
179     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
180     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
181     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
182 
183     /**
184      * @tc.steps:step2. update cloud data and merge
185      * @tc.expected: step2. check the changeddata and return ok
186      */
187     InitExpectChangedData(ChangedDataType::DATA, cloudCount, ChangeType::OP_UPDATE);
188     CloudDBSyncUtilsTest::UpdateCloudTableRecord(0, cloudCount, paddingSize, true, g_virtualCloudDb);
189     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
190     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
191     g_observer->ClearChangedData();
192     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
193     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
194 }
195 
196 /*
197  * @tc.name: CloudSyncTest003
198  * @tc.desc: test data sync when cloud delete
199  * @tc.type: FUNC
200  * @tc.require:
201  * @tc.author: chenchaohao
202  */
203 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest003, TestSize.Level0)
204 {
205     /**
206      * @tc.steps:step1. insert cloud data and merge
207      * @tc.expected: step1. check the changeddata and return ok
208      */
209     int64_t cloudCount = 10; // 10 is random cloud count
210     int64_t paddingSize = 10; // 10 is padding size
211     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, true, g_virtualCloudDb);
212     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
213     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
214     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
215 
216     /**
217      * @tc.steps:step2. delete cloud data and merge
218      * @tc.expected: step2. check the changeddata and return ok
219      */
220     InitExpectChangedData(ChangedDataType::DATA, cloudCount, ChangeType::OP_DELETE);
221     CloudDBSyncUtilsTest::DeleteCloudTableRecordByGid(0, cloudCount, g_virtualCloudDb);
222     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
223     CloudDBSyncUtilsTest::CheckCloudTotalCount({0L}, g_virtualCloudDb);
224     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
225     g_observer->ClearChangedData();
226     CloudDBSyncUtilsTest::CheckLocalRecordNum(db, g_tableName, 0);
227 }
228 
229 /*
230  * @tc.name: CloudSyncTest004
231  * @tc.desc: test asset when cloud insert
232  * @tc.type: FUNC
233  * @tc.require:
234  * @tc.author: chenchaohao
235  */
236 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest004, TestSize.Level0)
237 {
238     /**
239      * @tc.steps:step1. insert cloud asset and merge
240      * @tc.expected: step1. check the changeddata and return ok
241      */
242     int64_t cloudCount = 10; // 10 is random cloud count
243     int64_t paddingSize = 10; // 10 is padding size
244     InitExpectChangedData(ChangedDataType::ASSET, cloudCount, ChangeType::OP_INSERT);
245     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, false, g_virtualCloudDb);
246     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
247     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
248     g_observer->ClearChangedData();
249     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
250     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
251 }
252 
253 /*
254  * @tc.name: CloudSyncTest005
255  * @tc.desc: test asset sync when cloud insert
256  * @tc.type: FUNC
257  * @tc.require:
258  * @tc.author: chenchaohao
259  */
260 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest005, TestSize.Level0)
261 {
262     /**
263      * @tc.steps:step1. insert cloud asset and merge
264      * @tc.expected: step1. check the changeddata and return ok
265      */
266     int64_t cloudCount = 10; // 10 is random cloud count
267     int64_t paddingSize = 10; // 10 is padding size
268     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, false, g_virtualCloudDb);
269     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
270     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
271     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
272 
273     /**
274      * @tc.steps:step2. update cloud asset and merge
275      * @tc.expected: step2. check the changeddata and return ok
276      */
277     InitExpectChangedData(ChangedDataType::ASSET, cloudCount, ChangeType::OP_UPDATE);
278     CloudDBSyncUtilsTest::UpdateCloudTableRecord(0, cloudCount, paddingSize, false, g_virtualCloudDb);
279     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
280     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
281     g_observer->ClearChangedData();
282     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
283     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
284 }
285 
286 /*
287  * @tc.name: CloudSyncTest006
288  * @tc.desc: test asset sync when cloud delete
289  * @tc.type: FUNC
290  * @tc.require:
291  * @tc.author: chenchaohao
292  */
293 HWTEST_F(DistributedDBCloudTableCompoundPrimaryKeySyncTest, CloudSyncTest006, TestSize.Level0)
294 {
295     /**
296      * @tc.steps:step1. insert cloud asset and merge
297      * @tc.expected: step1. check the changeddata and return ok
298      */
299     int64_t cloudCount = 10; // 10 is random cloud count
300     int64_t paddingSize = 10; // 10 is padding size
301     CloudDBSyncUtilsTest::InsertCloudTableRecord(0, cloudCount, paddingSize, false, g_virtualCloudDb);
302     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
303     CloudDBSyncUtilsTest::CheckDownloadResult(db, {cloudCount}, CLOUD);
304     CloudDBSyncUtilsTest::CheckCloudTotalCount({cloudCount}, g_virtualCloudDb);
305 
306     /**
307      * @tc.steps:step2. insert cloud asset and merge
308      * @tc.expected: step2. check the changeddata and return ok
309      */
310     InitExpectChangedData(ChangedDataType::ASSET, cloudCount, ChangeType::OP_DELETE);
311     CloudDBSyncUtilsTest::DeleteCloudTableRecordByGid(0, cloudCount, g_virtualCloudDb);
312     CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate);
313     CloudDBSyncUtilsTest::CheckCloudTotalCount({0L}, g_virtualCloudDb);
314     EXPECT_TRUE(g_observer->IsAllChangedDataEq());
315     g_observer->ClearChangedData();
316     CloudDBSyncUtilsTest::CheckLocalRecordNum(db, g_tableName, 0);
317 }
318 
319 }
320 #endif // RELATIONAL_STORE