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
18 #include "cloud/cloud_db_constant.h"
19 #include "distributeddb_data_generate_unit_test.h"
20 #include "distributeddb_tools_unit_test.h"
21 #include "log_table_manager_factory.h"
22 #include "query_sync_object.h"
23 #include "relational_store_instance.h"
24 #include "relational_store_manager.h"
25 #include "relational_sync_able_storage.h"
26 #include "runtime_config.h"
27 #include "sqlite_relational_store.h"
28 #include "time_helper.h"
29 #include "virtual_asset_loader.h"
30 #include "virtual_cloud_data_translate.h"
31
32
33 using namespace testing::ext;
34 using namespace DistributedDB;
35 using namespace DistributedDBUnitTest;
36 using namespace std;
37
38 namespace {
39 string g_storeID = "Relational_Store_ID";
40 string g_tableName = "cloudData";
41 string g_logTblName;
42 string g_testDir;
43 string g_storePath;
44 const Timestamp g_startTime = 100000;
45 const int g_deleteFlag = 0x01;
46 const int g_localFlag = 0x02;
47 const std::string CREATE_LOCAL_TABLE_SQL =
48 "CREATE TABLE IF NOT EXISTS " + g_tableName + "(" \
49 "name TEXT ," \
50 "height REAL ," \
51 "married INT ," \
52 "photo BLOB ," \
53 "assert BLOB," \
54 "asserts BLOB," \
55 "age INT);";
56 const std::vector<Field> g_cloudFiled = {
57 {"name", TYPE_INDEX<std::string>}, {"age", TYPE_INDEX<int64_t>},
58 {"height", TYPE_INDEX<double>}, {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>},
59 {"assert", TYPE_INDEX<Asset>}, {"asserts", TYPE_INDEX<Assets>}
60 };
61 const Asset g_localAsset = {
62 .version = 1, .name = "Phone", .assetId = "0", .subpath = "/local/sync", .uri = "/local/sync",
63 .modifyTime = "123456", .createTime = "", .size = "256", .hash = " ",
64 .flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE), .status = static_cast<uint32_t>(AssetStatus::NORMAL),
65 .timestamp = 0L
66 };
67 DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
68 RelationalStoreDelegate *g_delegate = nullptr;
69 IRelationalStore *g_store = nullptr;
70 ICloudSyncStorageInterface *g_cloudStore = nullptr;
71 std::shared_ptr<StorageProxy> g_storageProxy = nullptr;
72 TableSchema g_tableSchema;
73
CreateDB()74 void CreateDB()
75 {
76 sqlite3 *db = nullptr;
77 int errCode = sqlite3_open(g_storePath.c_str(), &db);
78 if (errCode != SQLITE_OK) {
79 LOGE("open db failed:%d", errCode);
80 sqlite3_close(db);
81 return;
82 }
83
84 const string sql =
85 "PRAGMA journal_mode=WAL;";
86 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
87 sqlite3_close(db);
88 }
89
CreateLogTable(const std::string & tableName)90 void CreateLogTable(const std::string &tableName)
91 {
92 TableInfo table;
93 table.SetTableName(tableName);
94 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
95 sqlite3 *db = nullptr;
96 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
97 auto tableManager =
98 LogTableManagerFactory::GetTableManager(DistributedTableMode::COLLABORATION, TableSyncType::CLOUD_COOPERATION);
99 int errCode = tableManager->CreateRelationalLogTable(db, table);
100 EXPECT_EQ(errCode, E_OK);
101 sqlite3_close(db);
102 }
103
CreateAndInitUserTable(int64_t count,int64_t photoSize,const Asset & expect)104 void CreateAndInitUserTable(int64_t count, int64_t photoSize, const Asset &expect)
105 {
106 sqlite3 *db = nullptr;
107 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
108
109 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
110 std::string photo(photoSize, 'v');
111 std::vector<uint8_t> assetBlob;
112 std::vector<uint8_t> assetsBlob;
113 Asset asset = expect;
114 int id = 0;
115 Assets assets;
116 asset.name = expect.name + std::to_string(id++);
117 assets.push_back(asset);
118 asset.name = expect.name + std::to_string(id++);
119 assets.push_back(asset);
120 int errCode;
121 ASSERT_EQ(RuntimeContext::GetInstance()->AssetToBlob(expect, assetBlob), E_OK);
122 ASSERT_EQ(RuntimeContext::GetInstance()->AssetsToBlob(assets, assetsBlob), E_OK);
123 for (int i = 1; i <= count; ++i) {
124 string sql = "INSERT OR REPLACE INTO " + g_tableName +
125 " (name, height, married, photo, assert, asserts, age) VALUES ('Tom" + std::to_string(i) +
126 "', '175.8', '0', '" + photo + "', ? , ?, '18');";
127 sqlite3_stmt *stmt = nullptr;
128 ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
129 if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) != E_OK) { // 1 is asset index
130 SQLiteUtils::ResetStatement(stmt, true, errCode);
131 }
132 if (SQLiteUtils::BindBlobToStatement(stmt, 2, assetsBlob, false) != E_OK) { // 2 is index of asserts
133 SQLiteUtils::ResetStatement(stmt, true, errCode);
134 }
135 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
136 SQLiteUtils::ResetStatement(stmt, true, errCode);
137 }
138 sqlite3_close(db);
139 }
140
InitLogData(int64_t insCount,int64_t updCount,int64_t delCount,int64_t excludeCount,const std::string & tableName)141 void InitLogData(int64_t insCount, int64_t updCount, int64_t delCount, int64_t excludeCount,
142 const std::string &tableName)
143 {
144 sqlite3 *db = nullptr;
145 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
146 std::string flag;
147 std::string cloudGid;
148 for (int64_t i = 1; i <= insCount + updCount + delCount + excludeCount; ++i) {
149 std::string index = std::to_string(i);
150 if (i <= insCount) {
151 flag = std::to_string(g_localFlag);
152 cloudGid = "''";
153 } else if (i > insCount && i <= insCount + updCount) {
154 flag = std::to_string(g_localFlag);
155 cloudGid = "'" + g_storeID + index + "'";
156 } else if (i > (insCount + updCount) && i <= (insCount + updCount + delCount)) {
157 flag = std::to_string(g_localFlag | g_deleteFlag);
158 cloudGid = "'" + g_storeID + index + "'";
159 } else {
160 flag = std::to_string(g_localFlag | g_deleteFlag);
161 cloudGid = "''";
162 }
163 Bytes hashKey(index.begin(), index.end());
164 string sql = "INSERT OR REPLACE INTO " + tableName +
165 " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cloud_gid)" +
166 " VALUES ('" + std::to_string(i) + "', '', '', '" + std::to_string(g_startTime + i) + "', '" +
167 std::to_string(g_startTime + i) + "','" + flag + "', ? , " + cloudGid + ");";
168 sqlite3_stmt *stmt = nullptr;
169 int errCode = E_OK;
170 EXPECT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
171 EXPECT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, hashKey, false), E_OK);
172 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
173 SQLiteUtils::ResetStatement(stmt, true, errCode);
174 }
175 sqlite3_close(db);
176 }
177
InitLogGid(int64_t count)178 void InitLogGid(int64_t count)
179 {
180 sqlite3 *db = nullptr;
181 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
182 for (int i = 1; i <= count; i++) {
183 string sql = "update " + g_logTblName + " set cloud_gid = '" + std::to_string(i) +
184 "' where data_key = " + std::to_string(i);
185 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
186 }
187 sqlite3_close(db);
188 }
189
UpdateLogGidAndHashKey(int64_t count)190 void UpdateLogGidAndHashKey(int64_t count)
191 {
192 sqlite3 *db = nullptr;
193 int errCode;
194 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
195 for (int i = 1; i <= count; i++) {
196 std::string id = std::to_string(i);
197 string sql = "update " + g_logTblName + " set cloud_gid = '" + id +
198 "' , hash_key = ? where data_key = " + id;
199 sqlite3_stmt *stmt = nullptr;
200 EXPECT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
201 Bytes hashKey(id.begin(), id.end());
202 EXPECT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, hashKey, false), E_OK);
203 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
204 SQLiteUtils::ResetStatement(stmt, true, errCode);
205 }
206 sqlite3_close(db);
207 }
208
CheckGetAsset(VBucket & assets,uint32_t status)209 void CheckGetAsset(VBucket &assets, uint32_t status)
210 {
211 EXPECT_EQ(assets.size(), 2u);
212 ASSERT_TRUE(assets["assert"].index() == TYPE_INDEX<Asset>);
213 ASSERT_TRUE(assets["asserts"].index() == TYPE_INDEX<Assets>);
214 Asset data1 = std::get<Asset>(assets["assert"]);
215 ASSERT_EQ(data1.status, status);
216 Assets data2 = std::get<Assets>(assets["asserts"]);
217 ASSERT_GT(data2.size(), 0u);
218 ASSERT_EQ(data2[0].status, static_cast<uint32_t>(AssetStatus::NORMAL));
219 }
220
InitLogicDelete(int64_t count)221 void InitLogicDelete(int64_t count)
222 {
223 sqlite3 *db = nullptr;
224 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
225 for (int i = 1; i <= count; i++) {
226 string sql = "update " + g_logTblName + " set flag = flag | 0x09"
227 " where data_key = " + std::to_string(i);
228 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
229 }
230 sqlite3_close(db);
231 }
232
ConstructMultiDownloadData(int64_t count,DownloadData & downloadData,std::vector<OpType> & opTypes)233 void ConstructMultiDownloadData(int64_t count, DownloadData &downloadData, std::vector<OpType> &opTypes)
234 {
235 for (size_t i = 1; i <= opTypes.size(); i++) {
236 Asset asset = g_localAsset;
237 Assets assets;
238 VBucket vBucket;
239 if (i <= 2) { // 2 is deleted or insert type
240 asset.flag = static_cast<uint32_t>(i == 1 ? AssetOpType::DELETE : AssetOpType::INSERT);
241 vBucket[CloudDbConstant::GID_FIELD] = (i == 1 ? std::to_string(i) : std::to_string(count + i));
242 } else {
243 asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
244 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
245 }
246 vBucket["assert"] = asset;
247 asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
248 assets.push_back(asset);
249 asset.flag = static_cast<uint32_t>(AssetOpType::INSERT);
250 assets.push_back(asset);
251 asset.flag = static_cast<uint32_t>(AssetOpType::DELETE);
252 assets.push_back(asset);
253 asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
254 assets.push_back(asset);
255 vBucket["asserts"] = assets;
256 std::string name = "lisi" + std::to_string(i);
257 vBucket["name"] = name;
258 vBucket["age"] = (int64_t)i;
259 int64_t mTime = static_cast<int64_t>(12345679L + i);
260 vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
261 vBucket[CloudDbConstant::CREATE_FIELD] = mTime;
262 downloadData.data.push_back(vBucket);
263 }
264 downloadData.opType = opTypes;
265 }
266
AddVersionToDownloadData(DownloadData & downloadData)267 void AddVersionToDownloadData(DownloadData &downloadData)
268 {
269 for (size_t i = 0; i < downloadData.data.size(); i++) {
270 downloadData.data[i].insert_or_assign(CloudDbConstant::VERSION_FIELD, std::string("11"));
271 }
272 }
273
AddCloudOwnerToDownloadData(DownloadData & downloadData)274 void AddCloudOwnerToDownloadData(DownloadData &downloadData)
275 {
276 for (size_t i = 0; i < downloadData.data.size(); i++) {
277 downloadData.data[i].insert_or_assign(CloudDbConstant::CLOUD_OWNER, std::to_string(i));
278 }
279 }
280
SetDbSchema(const TableSchema & tableSchema)281 void SetDbSchema(const TableSchema &tableSchema)
282 {
283 DataBaseSchema dataBaseSchema;
284 dataBaseSchema.tables.push_back(tableSchema);
285 EXPECT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK);
286 }
287
InitUserDataForAssetTest(int64_t insCount,int64_t photoSize,const Asset & expect)288 void InitUserDataForAssetTest(int64_t insCount, int64_t photoSize, const Asset &expect)
289 {
290 sqlite3 *db = nullptr;
291 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
292 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
293 sqlite3_close(db);
294 EXPECT_EQ(g_delegate->CreateDistributedTable(g_tableName, DistributedDB::CLOUD_COOPERATION), OK);
295 CreateAndInitUserTable(insCount, photoSize, expect);
296 SetDbSchema(g_tableSchema);
297 }
298
QueryCountCallback(void * data,int count,char ** colValue,char ** colName)299 int QueryCountCallback(void *data, int count, char **colValue, char **colName)
300 {
301 if (count != 1) {
302 return 0;
303 }
304 auto expectCount = reinterpret_cast<int64_t>(data);
305 EXPECT_EQ(strtol(colValue[0], nullptr, 10), expectCount); // 10: decimal
306 return 0;
307 }
308
fillCloudAssetTest(int64_t count,AssetStatus statusType,bool isDownloadSuccess)309 void fillCloudAssetTest(int64_t count, AssetStatus statusType, bool isDownloadSuccess)
310 {
311 VBucket vBucket;
312 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(1);
313 for (int i = 0; i < 4; i ++) { // 4 is AssetStatus Num
314 Asset asset = g_localAsset;
315 asset.flag = static_cast<uint32_t>(i);
316 asset.status = static_cast<uint32_t>(statusType);
317 asset.timestamp = g_startTime;
318 Assets assets;
319 for (int j = 0; j < 4; j++) { // 4 is AssetStatus Num
320 Asset temp = g_localAsset;
321 temp.flag = static_cast<uint32_t>(j);
322 temp.status = static_cast<uint32_t>(statusType);
323 temp.timestamp = g_startTime + j;
324 assets.push_back(temp);
325 }
326 vBucket["assert"] = asset;
327 vBucket["asserts"] = assets;
328 ASSERT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
329 ASSERT_EQ(g_storageProxy->FillCloudAssetForDownload(g_tableName, vBucket, isDownloadSuccess), E_OK);
330 ASSERT_EQ(g_storageProxy->Commit(), E_OK);
331 }
332 }
333
UpdateLocalAsset(const std::string & tableName,Asset & asset,int64_t rowid)334 void UpdateLocalAsset(const std::string &tableName, Asset &asset, int64_t rowid)
335 {
336 sqlite3 *db = nullptr;
337 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
338 string sql = "UPDATE " + tableName + " SET assert = ? where rowid = '" + std::to_string(rowid) + "';";
339 std::vector<uint8_t> assetBlob;
340 int errCode;
341 RuntimeContext::GetInstance()->AssetToBlob(asset, assetBlob);
342 sqlite3_stmt *stmt = nullptr;
343 ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
344 if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) == E_OK) {
345 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
346 }
347 SQLiteUtils::ResetStatement(stmt, true, errCode);
348 sqlite3_close(db);
349 }
350
InitStoreProp(const std::string & storePath,const std::string & appId,const std::string & userId,RelationalDBProperties & properties)351 void InitStoreProp(const std::string &storePath, const std::string &appId, const std::string &userId,
352 RelationalDBProperties &properties)
353 {
354 properties.SetStringProp(RelationalDBProperties::DATA_DIR, storePath);
355 properties.SetStringProp(RelationalDBProperties::APP_ID, appId);
356 properties.SetStringProp(RelationalDBProperties::USER_ID, userId);
357 properties.SetStringProp(RelationalDBProperties::STORE_ID, g_storeID);
358 std::string identifier = userId + "-" + appId + "-" + g_storeID;
359 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
360 properties.SetStringProp(RelationalDBProperties::IDENTIFIER_DATA, hashIdentifier);
361 }
362
GetRelationalStore()363 const RelationalSyncAbleStorage *GetRelationalStore()
364 {
365 RelationalDBProperties properties;
366 InitStoreProp(g_storePath, APP_ID, USER_ID, properties);
367 int errCode = E_OK;
368 g_store = RelationalStoreInstance::GetDataBase(properties, errCode);
369 if (g_store == nullptr) {
370 LOGE("Get db failed:%d", errCode);
371 return nullptr;
372 }
373 return static_cast<SQLiteRelationalStore *>(g_store)->GetStorageEngine();
374 }
375
GetStorageProxy(ICloudSyncStorageInterface * store)376 std::shared_ptr<StorageProxy> GetStorageProxy(ICloudSyncStorageInterface *store)
377 {
378 return StorageProxy::GetCloudDb(store);
379 }
380
381 class DistributedDBRelationalCloudSyncableStorageTest : public testing::Test {
382 public:
383 static void SetUpTestCase(void);
384 static void TearDownTestCase(void);
385 void SetUp();
386 void TearDown();
387 };
388
389
SetUpTestCase(void)390 void DistributedDBRelationalCloudSyncableStorageTest::SetUpTestCase(void)
391 {
392 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
393 g_storePath = g_testDir + "/cloudDataTest.db";
394 g_logTblName = DBConstant::RELATIONAL_PREFIX + g_tableName + "_log";
395 LOGI("The test db is:%s", g_testDir.c_str());
396 RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
397 g_tableSchema.name = g_tableName;
398 g_tableSchema.sharedTableName = g_tableName + "_shared";
399 g_tableSchema.fields = g_cloudFiled;
400 }
401
TearDownTestCase(void)402 void DistributedDBRelationalCloudSyncableStorageTest::TearDownTestCase(void)
403 {}
404
SetUp(void)405 void DistributedDBRelationalCloudSyncableStorageTest::SetUp(void)
406 {
407 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
408 LOGE("rm test db files error.");
409 }
410 DistributedDBToolsUnitTest::PrintTestCaseInfo();
411 LOGD("Test dir is %s", g_testDir.c_str());
412 CreateDB();
413 ASSERT_EQ(g_mgr.OpenStore(g_storePath, g_storeID, RelationalStoreDelegate::Option {}, g_delegate), DBStatus::OK);
414 ASSERT_NE(g_delegate, nullptr);
415 g_cloudStore = (ICloudSyncStorageInterface *) GetRelationalStore();
416 ASSERT_NE(g_cloudStore, nullptr);
417 g_storageProxy = GetStorageProxy(g_cloudStore);
418 ASSERT_NE(g_storageProxy, nullptr);
419 ASSERT_EQ(g_delegate->SetIAssetLoader(std::make_shared<VirtualAssetLoader>()), DBStatus::OK);
420 }
421
TearDown(void)422 void DistributedDBRelationalCloudSyncableStorageTest::TearDown(void)
423 {
424 RefObject::DecObjRef(g_store);
425 if (g_delegate != nullptr) {
426 EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK);
427 g_delegate = nullptr;
428 }
429 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
430 LOGE("rm test db files error.");
431 }
432 }
433
434 /**
435 * @tc.name: MetaDataTest001
436 * @tc.desc: Test PutMetaData and GetMetaData from ICloudSyncStorageInterface impl class
437 * @tc.type: FUNC
438 * @tc.require:
439 * @tc.author: bty
440 */
441 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest001, TestSize.Level0)
442 {
443 EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_2), E_OK);
444 EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_3), E_OK);
445
446 Value value;
447 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
448 EXPECT_EQ(value, VALUE_3);
449 }
450
451 /**
452 * @tc.name: MetaDataTest002
453 * @tc.desc: The GetMetaData supports key sizes up to 1024
454 * @tc.type: FUNC
455 * @tc.require:
456 * @tc.author: bty
457 */
458 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest002, TestSize.Level0)
459 {
460 const string str(DBConstant::MAX_KEY_SIZE, 'k');
461 const Key key(str.begin(), str.end());
462 EXPECT_EQ(g_cloudStore->PutMetaData(key, VALUE_2), E_OK);
463 Value value;
464 EXPECT_EQ(g_cloudStore->GetMetaData(key, value), E_OK);
465 EXPECT_EQ(value, VALUE_2);
466
467 const string maxStr(DBConstant::MAX_KEY_SIZE + 1, 'k');
468 const Key maxKey(maxStr.begin(), maxStr.end());
469 EXPECT_EQ(g_cloudStore->PutMetaData(maxKey, VALUE_3), E_OK);
470 EXPECT_EQ(g_cloudStore->GetMetaData(maxKey, value), -E_INVALID_ARGS);
471 }
472
473 /**
474 * @tc.name: TransactionTest001
475 * @tc.desc: No write transaction in the current store, meta interface can called
476 * @tc.type: FUNC
477 * @tc.require:
478 * @tc.author: bty
479 */
480 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest001, TestSize.Level0)
481 {
482 /**
483 * @tc.steps: allow get or put meta in read transaction
484 * @tc.expected: Succeed, return OK.
485 */
486 EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
487 g_cloudStore->PutMetaData(KEY_1, VALUE_1);
488 EXPECT_EQ(g_cloudStore->Rollback(), E_OK);
489 g_cloudStore->PutMetaData(KEY_2, VALUE_2);
490
491 Value value;
492 EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
493 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
494 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_2, value), E_OK);
495 g_cloudStore->PutMetaData(KEY_3, VALUE_3);
496 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
497 EXPECT_EQ(g_cloudStore->Commit(), E_OK);
498 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
499 }
500
501 /**
502 * @tc.name: TransactionTest002
503 * @tc.desc: Test transaction interface from StorageProxy
504 * @tc.type: FUNC
505 * @tc.require:
506 * @tc.author: bty
507 */
508 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest002, TestSize.Level0)
509 {
510 Timestamp cloudTime = 666888;
511 Timestamp localTime;
512 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
513
514 /**
515 * @tc.steps: allow get or put waterMark in read transaction
516 * @tc.expected: Succeed, return OK.
517 */
518 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
519 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
520 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
521 EXPECT_EQ(cloudTime, localTime);
522 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
523 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
524
525 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
526 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
527 cloudTime = 999666;
528 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
529 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
530 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
531 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
532 EXPECT_EQ(cloudTime, localTime);
533
534 /**
535 * @tc.steps: not allow get or put waterMark in write transaction
536 * @tc.expected: return -E_BUSY.
537 */
538 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
539 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), -E_BUSY);
540 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), -E_BUSY);
541 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
542 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
543 }
544
545 /**
546 * @tc.name: TransactionTest003
547 * @tc.desc: Repeatedly call transaction interface from StorageProxy
548 * @tc.type: FUNC
549 * @tc.require:
550 * @tc.author: bty
551 */
552 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest003, TestSize.Level0)
553 {
554 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
555
556 /**
557 * @tc.steps: Repeated start transactions is not allowed
558 * @tc.expected: return -E_TRANSACT_STATE.
559 */
560 EXPECT_EQ(g_storageProxy->StartTransaction(), -E_TRANSACT_STATE);
561
562 /**
563 * @tc.steps: Repeated commit is not allowed
564 * @tc.expected: return -E_INVALID_DB.
565 */
566 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
567 EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
568
569 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
570
571 /**
572 * @tc.steps: Repeated Rollback is not allowed
573 * @tc.expected: return -E_INVALID_DB.
574 */
575 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
576 EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
577 }
578
579 /**
580 * @tc.name: TransactionTest004
581 * @tc.desc: Call transaction after close storageProxy
582 * @tc.type: FUNC
583 * @tc.require:
584 * @tc.author: bty
585 */
586 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest004, TestSize.Level0)
587 {
588 /**
589 * @tc.steps: transaction is not allowed after closing the proxy
590 * @tc.expected: return -E_INVALID_DB.
591 */
592 EXPECT_EQ(g_storageProxy->Close(), E_OK);
593 EXPECT_EQ(g_storageProxy->StartTransaction(), -E_INVALID_DB);
594 EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
595 EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
596
597 g_storageProxy = GetStorageProxy(g_cloudStore);
598 ASSERT_NE(g_storageProxy, nullptr);
599 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
600
601 /**
602 * @tc.steps: close proxy is not allowed before the transaction has been commit or rollback
603 * @tc.expected: return -E_BUSY.
604 */
605 EXPECT_EQ(g_storageProxy->Close(), -E_BUSY);
606 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
607 EXPECT_EQ(g_storageProxy->Close(), E_OK);
608 }
609
610 /**
611 * @tc.name: GetUploadCount001
612 * @tc.desc: Test getUploadCount by ICloudSyncStorageInterface
613 * @tc.type: FUNC
614 * @tc.require:
615 * @tc.author: bty
616 */
617 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount001, TestSize.Level0)
618 {
619 /**
620 * @tc.steps: Table does not exist
621 * @tc.expected: return -SQLITE_ERROR.
622 */
623 int64_t resCount = 0;
624 QuerySyncObject query;
625 query.SetTableName(g_tableName);
626 EXPECT_EQ(g_cloudStore->GetUploadCount(query, g_startTime, false, false, resCount), -E_INVALID_QUERY_FORMAT);
627
628 CreateLogTable(g_tableName);
629 int64_t insCount = 100;
630 CreateAndInitUserTable(insCount, insCount, g_localAsset);
631 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
632 EXPECT_EQ(g_cloudStore->GetUploadCount(query, g_startTime, false, false, resCount), E_OK);
633 EXPECT_EQ(resCount, insCount + insCount + insCount);
634
635 /**
636 * @tc.steps: Timestamp filtering will not work.
637 * @tc.expected: count is 300 and return E_OK.
638 */
639 Timestamp invalidTime = g_startTime + g_startTime;
640 EXPECT_EQ(g_cloudStore->GetUploadCount(query, invalidTime, false, false, resCount), E_OK);
641 EXPECT_EQ(resCount, insCount + insCount + insCount);
642 }
643
644 /**
645 * @tc.name: GetUploadCount002
646 * @tc.desc: Test getUploadCount by storageProxy
647 * @tc.type: FUNC
648 * @tc.require:
649 * @tc.author: bty
650 */
651 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount002, TestSize.Level0)
652 {
653 CreateLogTable(g_tableName);
654 int64_t insCount = 100;
655 InitLogData(insCount, insCount, 0, insCount, g_logTblName);
656 CreateAndInitUserTable(insCount, insCount, g_localAsset);
657 int64_t resCount = 0;
658
659 /**
660 * @tc.steps: GetUploadCount must be called under transaction
661 * @tc.expected: return -E_TRANSACT_STATE.
662 */
663 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
664
665 int timeOffset = 30;
666 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
667 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
668 // Timestamp filtering will not work.
669 EXPECT_EQ(resCount, insCount + insCount);
670 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
671
672 /**
673 * @tc.steps: GetUploadCount also can be called under write transaction
674 * @tc.expected: return E_OK.
675 */
676 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
677 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
678 // Timestamp filtering will not work.
679 EXPECT_EQ(resCount, insCount + insCount);
680 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
681 }
682
683 /**
684 * @tc.name: GetUploadCount003
685 * @tc.desc: Test getUploadCount exclude condition of (deleteFlag and cloud_gid is '')
686 * @tc.type: FUNC
687 * @tc.require:
688 * @tc.author: bty
689 */
690 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount003, TestSize.Level0)
691 {
692 CreateLogTable(g_tableName);
693 int64_t insCount = 100;
694 CreateAndInitUserTable(insCount, insCount, g_localAsset);
695 InitLogData(0, 0, insCount, insCount, g_logTblName);
696 int64_t resCount = 0;
697
698 /**
699 * @tc.steps: GetUploadCount must be called under transaction
700 * @tc.expected: return -E_TRANSACT_STATE.
701 */
702 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
703
704 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
705 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
706 EXPECT_EQ(resCount, insCount);
707 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
708 }
709
710 /**
711 * @tc.name: GetUploadCount004
712 * @tc.desc: Test getUploadCount and ExecuteSql concurrently
713 * @tc.type: FUNC
714 * @tc.require:
715 * @tc.author: liaoyonghuang
716 */
717 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount004, TestSize.Level1)
718 {
719 /**
720 * @tc.step1: Init data
721 * @tc.expected: step1. return OK
722 */
723 CreateLogTable(g_tableName);
724 int64_t insCount = 100;
725 CreateAndInitUserTable(insCount, insCount, g_localAsset);
726 InitLogData(0, 0, insCount, insCount, g_logTblName);
727 int64_t resCount = 0;
728 /**
729 * @tc.step2: GetUploadCount and ExecuteSql concurrently
730 * @tc.expected: step2. return OK.
731 */
__anonb3e9f8950202() 732 std::thread getUploadCountThread([&]() {
733 for (int i = 0; i < 100; i++) {
734 if (g_storageProxy->StartTransaction() == E_OK) {
735 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
736 EXPECT_EQ(resCount, insCount);
737 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
738 }
739 }
740 });
__anonb3e9f8950302() 741 std::thread execThread([&]() {
742 DistributedDB::SqlCondition sqlCondition;
743 sqlCondition.readOnly = true;
744 for (int i = 0; i < 100; i++) {
745 std::vector<VBucket> records = {};
746 sqlCondition.sql = "BEGIN;";
747 EXPECT_EQ(g_delegate->ExecuteSql(sqlCondition, records), E_OK);
748 std::this_thread::sleep_for(std::chrono::milliseconds(1));
749 sqlCondition.sql = "COMMIT;";
750 EXPECT_EQ(g_delegate->ExecuteSql(sqlCondition, records), E_OK);
751 }
752 });
753 execThread.join();
754 getUploadCountThread.join();
755 }
756
757 /**
758 * @tc.name: FillCloudGid001
759 * @tc.desc: FillCloudGid with invalid parm
760 * @tc.type: FUNC
761 * @tc.require:
762 * @tc.author: bty
763 */
764 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid001, TestSize.Level0)
765 {
766 CreateLogTable(g_tableName);
767 int64_t insCount = 100;
768 InitLogData(insCount, 0, insCount, insCount, g_logTblName);
769 CreateAndInitUserTable(0, 0, {});
770 CloudSyncData syncData(g_tableName);
771 SetDbSchema(g_tableSchema);
772
773 /**
774 * @tc.steps: rowid set is empty
775 * @tc.expected: return -E_INVALID_ARGS.
776 */
777 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
778 syncData.insData.rowid.push_back(1);
779 syncData.insData.rowid.push_back(2); // 2 is random id
780
781 /**
782 * @tc.steps: insData set is empty
783 * @tc.expected: return -E_INVALID_ARGS.
784 */
785 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
786 VBucket bucket1;
787 bucket1.insert_or_assign(g_tableName, g_tableName);
788 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, 1L);
789 syncData.insData.extend.push_back(bucket1);
790
791 /**
792 * @tc.steps: the size of rowid and insData is not equal
793 * @tc.expected: return -E_INVALID_ARGS.
794 */
795 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
796
797 /**
798 * @tc.steps: table name is empty
799 * @tc.expected: return -SQLITE_ERROR.
800 */
801 VBucket bucket2;
802 bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, 2L); // 2L is random field
803 syncData.insData.extend.push_back(bucket2);
804 syncData.tableName = "";
805 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_NOT_FOUND);
806
807 /**
808 * @tc.steps: the field type does not match
809 * @tc.expected: return -E_CLOUD_ERROR.
810 */
811 syncData.tableName = g_tableName;
812 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_CLOUD_ERROR);
813
814 /**
815 * @tc.steps: missing field GID_FIELD
816 * @tc.expected: return -E_INVALID_ARGS.
817 */
818 syncData.insData.extend.clear();
819 Timestamp now = TimeHelper::GetSysCurrentTime();
820 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("1"));
821 bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, std::string("2"));
822 syncData.insData.timestamp.push_back((int64_t)now / CloudDbConstant::TEN_THOUSAND);
823 syncData.insData.timestamp.push_back((int64_t)now / CloudDbConstant::TEN_THOUSAND);
824 syncData.insData.extend.push_back(bucket1);
825 syncData.insData.extend.push_back(bucket2);
826 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
827
828 syncData.insData.extend.pop_back();
829 bucket2.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("2"));
830 syncData.insData.extend.push_back(bucket2);
831 syncData.insData.hashKey.push_back({'3', '3'});
832 syncData.insData.hashKey.push_back({'3', '3'});
833 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), E_OK);
834
835 /**
836 * @tc.steps: table name is not exists
837 * @tc.expected: return -SQLITE_ERROR.
838 */
839 syncData.tableName = "noneTable";
840 EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_NOT_FOUND);
841 }
842
843 /**
844 * @tc.name: GetCloudData003
845 * @tc.desc: ReleaseContinueToken required when GetCloudDataNext interrupt
846 * @tc.type: FUNC
847 * @tc.require:
848 * @tc.author: bty
849 */
850 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData003, TestSize.Level0)
851 {
852 CreateLogTable(g_tableName);
853 int64_t insCount = 1024;
854 int64_t photoSize = 1024 * 8;
855 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
856 CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
857
858 SetDbSchema(g_tableSchema);
859 ContinueToken token = nullptr;
860 CloudSyncData cloudSyncData(g_tableName);
861 EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
862 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
863 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
864 ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
865 token = nullptr;
866 EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData), -E_INVALID_ARGS);
867 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
868
869 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
870 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
871 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
872 ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
873 }
874
875 /**
876 * @tc.name: GetCloudData004
877 * @tc.desc: Test get cloudData when asset or assets is NULL
878 * @tc.type: FUNC
879 * @tc.require:
880 * @tc.author: bty
881 */
882 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData004, TestSize.Level0)
883 {
884 CreateLogTable(g_tableName);
885 int64_t insCount = 10;
886 int64_t photoSize = 10;
887 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
888 CreateAndInitUserTable(3 * insCount, photoSize, g_localAsset); // 3 is insert,update and delete type data
889
890 SetDbSchema(g_tableSchema);
891 sqlite3 *db = nullptr;
892 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
893 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, "UPDATE " + g_tableName + " SET assert = NULL, asserts = NULL;"), E_OK);
894 sqlite3_close(db);
895 ContinueToken token = nullptr;
896 CloudSyncData cloudSyncData(g_tableName);
897 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
898 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
899 EXPECT_NE(cloudSyncData.insData.record.size(), 0u);
900 for (const auto &item: cloudSyncData.insData.record) {
901 auto assert = item.find("assert");
902 auto asserts = item.find("asserts");
903 ASSERT_NE(assert, item.end());
904 ASSERT_NE(asserts, item.end());
905 EXPECT_EQ(assert->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
906 EXPECT_EQ(asserts->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
907 }
908 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
909 }
910
911 /**
912 * @tc.name: GetCloudData005
913 * @tc.desc: Commit the transaction before getCloudData finished
914 * @tc.type: FUNC
915 * @tc.require:
916 * @tc.author: bty
917 */
918 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData005, TestSize.Level0)
919 {
920 CreateLogTable(g_tableName);
921 int64_t insCount = 1024;
922 int64_t photoSize = 1024 * 8;
923 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
924 CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
925
926 SetDbSchema(g_tableSchema);
927 ContinueToken token = nullptr;
928 CloudSyncData cloudSyncData(g_tableName);
929 EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
930 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
931 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
932 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
933
934 /**
935 * @tc.steps: GetCloudDataNext after the transaction ends, token will released internally
936 * @tc.expected: return -E_INVALID_DB.
937 */
938 ASSERT_EQ(g_cloudStore->GetCloudDataNext(token, cloudSyncData), -E_INVALID_DB);
939 }
940
941 /**
942 * @tc.name: GetCloudData006
943 * @tc.desc: Test get cloud data which contains invalid status asset
944 * @tc.type: FUNC
945 * @tc.require:
946 * @tc.author: bty
947 */
948 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData006, TestSize.Level0)
949 {
950 /**
951 * @tc.steps:step1. Init data and set asset status to invalid num
952 * @tc.expected: step1. return ok.
953 */
954 CreateLogTable(g_tableName);
955 int64_t insCount = 1024;
956 int64_t photoSize = 1024;
957 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
958 CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
959 Asset asset = g_localAsset;
960 asset.status = static_cast<uint32_t>(AssetStatus::UPDATE) + 1;
961 UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
962 SetDbSchema(g_tableSchema);
963
964 /**
965 * @tc.steps:step2. Get cloud data
966 * @tc.expected: step2. return -E_CLOUD_ERROR.
967 */
968 ContinueToken token = nullptr;
969 CloudSyncData cloudSyncData;
970 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
971 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_CLOUD_ERROR);
972 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
973 }
974
975 /**
976 * @tc.name: GetCloudData008
977 * @tc.desc: GetCloudGid other table after GetCloudData.
978 * @tc.type: FUNC
979 * @tc.require:
980 * @tc.author: liaoyonghuang
981 */
982 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData008, TestSize.Level0)
983 {
984 /**
985 * @tc.steps:step1. table1
986 * @tc.expected: step1. return ok.
987 */
988 CreateLogTable(g_tableName);
989 int64_t insCount = 10;
990 int64_t photoSize = 10;
991 InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
992 CreateAndInitUserTable(3 * insCount, photoSize, g_localAsset); // 3 is insert,update and delete type data
993
994 /**
995 * @tc.steps:step2. table2
996 * @tc.expected: step2. return ok.
997 */
998 std::string tableName2 = "cloudData2";
999 std::string logTblName2 = DBConstant::RELATIONAL_PREFIX + tableName2 + "_log";
1000 CreateLogTable(tableName2);
1001 InitLogData(insCount, insCount, insCount, insCount, logTblName2);
1002 sqlite3 *db = nullptr;
1003 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1004 std::string createTable2Sql = "CREATE TABLE IF NOT EXISTS " + tableName2 + "(name TEXT ,age INT);";
1005 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, createTable2Sql), E_OK);
1006 sqlite3_close(db);
1007 const std::vector<Field> cloudField2 = {{"name", TYPE_INDEX<std::string>}, {"age", TYPE_INDEX<int64_t>}};
1008 TableSchema tableSchema2;
1009 tableSchema2.name = tableName2;
1010 tableSchema2.sharedTableName = tableName2 + "_shared";
1011 tableSchema2.fields = cloudField2;
1012 DataBaseSchema dataBaseSchema;
1013 dataBaseSchema.tables.push_back(g_tableSchema);
1014 dataBaseSchema.tables.push_back(tableSchema2);
1015 EXPECT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK);
1016
1017 /**
1018 * @tc.steps:step3. GetCloudData from table1, then GetCloudGid from table2
1019 * @tc.expected: step3. return ok.
1020 */
1021 ContinueToken token = nullptr;
1022 CloudSyncData cloudSyncData(g_tableName);
1023 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1024 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
1025 QuerySyncObject obj;
1026 obj.SetTableName(tableName2);
1027 std::vector<std::string> cloudGid;
1028 EXPECT_EQ(g_storageProxy->GetCloudGid(obj, false, false, cloudGid), E_OK);
1029 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1030 }
1031
1032 /**
1033 * @tc.name: GetInfoByPrimaryKeyOrGid001
1034 * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1035 * @tc.type: FUNC
1036 * @tc.require:
1037 * @tc.author: bty
1038 */
1039 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid001, TestSize.Level0)
1040 {
1041 int64_t insCount = 100;
1042 int64_t photoSize = 10;
1043 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1044 InitLogGid(insCount);
1045
1046 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1047 for (int i = 1; i <= insCount; i++) {
1048 VBucket vBucket;
1049 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1050 VBucket assetInfo;
1051 DataInfoWithLog dataInfo;
1052 ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK);
1053 ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1054 auto entry1 = assetInfo.find("assert");
1055 auto entry2 = assetInfo.find("asserts");
1056 ASSERT_NE(entry1, assetInfo.end());
1057 ASSERT_NE(entry2, assetInfo.end());
1058 Asset asset = std::get<Asset>(entry1->second);
1059 EXPECT_EQ(asset.name, "Phone");
1060 Assets assets = std::get<Assets>(entry2->second);
1061 int id = 0;
1062 for (const auto &item: assets) {
1063 EXPECT_EQ(item.name, "Phone" + std::to_string(id++));
1064 }
1065 }
1066 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1067 }
1068
1069 /**
1070 * @tc.name: GetInfoByPrimaryKeyOrGid002
1071 * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1072 * @tc.type: FUNC
1073 * @tc.require:
1074 * @tc.author: zqq
1075 */
1076 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid002, TestSize.Level0)
1077 {
1078 int64_t insCount = 5;
1079 int64_t photoSize = 1;
1080 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1081 InitLogGid(insCount);
1082 InitLogicDelete(insCount);
1083
1084 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1085 for (int i = 1; i <= insCount; i++) {
1086 VBucket vBucket;
1087 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1088 VBucket assetInfo;
1089 DataInfoWithLog dataInfo;
1090 ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK);
1091 ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1092 EXPECT_EQ(assetInfo.size(), 0u);
1093 }
1094 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1095 }
1096
1097 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncData001, TestSize.Level0)
1098 {
1099 int64_t insCount = 10;
1100 int64_t photoSize = 10;
1101 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1102 InitLogGid(insCount);
1103
1104 DownloadData downloadData;
1105 std::vector<OpType> opTypes = { OpType::DELETE, OpType::INSERT, OpType::UPDATE,
1106 OpType::UPDATE, OpType::NOT_HANDLE };
1107 ConstructMultiDownloadData(insCount, downloadData, opTypes);
1108 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1109 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1110 ContinueToken token = nullptr;
1111 CloudSyncData cloudSyncData;
1112 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, 0L, token, cloudSyncData), E_OK);
1113 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1114 }
1115
1116 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset001, TestSize.Level0)
1117 {
1118 int64_t insCount = 10;
1119 int64_t photoSize = 10;
1120 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1121 InitLogGid(insCount);
1122 fillCloudAssetTest(insCount, AssetStatus::NORMAL, false);
1123 fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, false);
1124 fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, false);
1125 fillCloudAssetTest(insCount, AssetStatus::NORMAL, true);
1126 fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, true);
1127 fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, true);
1128 }
1129
1130 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, TestSize.Level0)
1131 {
1132 int64_t insCount = 10;
1133 int64_t photoSize = 10;
1134 Asset asset1 = g_localAsset;
1135 asset1.status = static_cast<uint32_t>(AssetStatus::DELETE | AssetStatus::UPLOADING);
1136 InitUserDataForAssetTest(insCount, photoSize, asset1);
1137 InitLogGid(insCount);
1138
1139 sqlite3 *db = nullptr;
1140 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1141 sqlite3_stmt *stmt = nullptr;
1142 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp, hash_key FROM " + DBCommon::GetLogTableName(g_tableName)
1143 + " WHERE data_key = 1;", stmt), E_OK);
1144 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1145 int64_t timeStamp = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1146 Bytes hashKey;
1147 int errCode = SQLiteUtils::GetColumnBlobValue(stmt, 1, hashKey); // 1 is hash_key index
1148 EXPECT_EQ(errCode, E_OK);
1149 SQLiteUtils::ResetStatement(stmt, true, errCode);
1150
1151 CloudSyncData syncData(g_tableName);
1152 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1153 ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1154 syncData.updData.rowid.push_back(1L);
1155 VBucket bucket1;
1156 Asset asset = g_localAsset;
1157 asset.size = "888";
1158 asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
1159 asset.status = static_cast<uint32_t>(AssetStatus::DELETE | AssetStatus::UPLOADING);
1160 bucket1.insert_or_assign("assert", asset);
1161 int id = 0;
1162 Assets assets;
1163 asset.name = asset1.name + std::to_string(id++);
1164 assets.push_back(asset);
1165 asset.name = asset1.name + std::to_string(id++);
1166 assets.push_back(asset);
1167 bucket1.insert_or_assign("asserts", assets);
1168 syncData.updData.assets.push_back(bucket1);
1169 syncData.updData.extend.push_back(bucket1);
1170 syncData.updData.timestamp.push_back(timeStamp);
1171 syncData.updData.hashKey.push_back(hashKey);
1172 ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1173 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1174
1175 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT assert, asserts FROM " + g_tableName + " WHERE rowid = 1;",
1176 stmt), E_OK);
1177 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1178 ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_NULL);
1179 ASSERT_EQ(sqlite3_column_type(stmt, 1), SQLITE_NULL);
1180 SQLiteUtils::ResetStatement(stmt, true, errCode);
1181 sqlite3_close(db);
1182 }
1183
1184 /**
1185 * @tc.name: FillCloudAsset003
1186 * @tc.desc: The twice fill have different assert columns
1187 * @tc.type: FUNC
1188 * @tc.require:
1189 * @tc.author: bty
1190 */
1191 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset003, TestSize.Level0)
1192 {
1193 int64_t insCount = 2;
1194 int64_t photoSize = 10;
1195 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1196 InitLogGid(insCount);
1197
1198 sqlite3 *db = nullptr;
1199 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1200 sqlite3_stmt *stmt = nullptr;
1201 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1202 " WHERE data_key in ('1', '2');", stmt), E_OK);
1203 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1204 int64_t timeStamp1 = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1205 int64_t timeStamp2 = static_cast<int64_t>(sqlite3_column_int64(stmt, 1));
1206 int errCode;
1207 SQLiteUtils::ResetStatement(stmt, true, errCode);
1208 sqlite3_close(db);
1209
1210 CloudSyncData syncData(g_tableName);
1211 syncData.updData.rowid.push_back(1L);
1212 syncData.updData.rowid.push_back(2L);
1213 VBucket bucket1, bucket2;
1214 Asset asset = g_localAsset;
1215 asset.size = "888";
1216 asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1217 Assets assets;
1218 assets.push_back(asset);
1219 assets.push_back(asset);
1220 bucket1.insert_or_assign("assert", asset);
1221 bucket2.insert_or_assign("assert", asset);
1222 bucket2.insert_or_assign("asserts", assets);
1223 syncData.updData.assets.push_back(bucket1);
1224 syncData.updData.assets.push_back(bucket2);
1225 syncData.updData.extend.push_back(bucket1);
1226 syncData.updData.extend.push_back(bucket2);
1227 syncData.updData.timestamp.push_back(timeStamp1);
1228 syncData.updData.timestamp.push_back(timeStamp2);
1229 syncData.updData.hashKey.push_back({ 1 });
1230 syncData.updData.hashKey.push_back({ 2 });
1231 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1232 ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1233 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1234 }
1235
1236 /**
1237 * @tc.name: FillCloudAsset004
1238 * @tc.desc: Test fill asset for insert type
1239 * @tc.type: FUNC
1240 * @tc.require:
1241 * @tc.author: bty
1242 */
1243 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset004, TestSize.Level0)
1244 {
1245 int64_t insCount = 2;
1246 int64_t photoSize = 10;
1247 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1248
1249 sqlite3 *db = nullptr;
1250 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1251 sqlite3_stmt *stmt = nullptr;
1252 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1253 " WHERE data_key in ('1', '2');", stmt), E_OK);
1254 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1255 std::vector<int64_t> timeVector;
1256 timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 0)));
1257 timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 1)));
1258 int errCode;
1259 SQLiteUtils::ResetStatement(stmt, true, errCode);
1260 sqlite3_close(db);
1261
1262 CloudSyncData syncData(g_tableName);
1263 for (int64_t i = 1; i <= insCount; ++i) {
1264 syncData.insData.rowid.push_back(i);
1265 VBucket bucket1;
1266 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i));
1267 syncData.insData.extend.push_back(bucket1);
1268
1269 VBucket bucket2;
1270 Asset asset = g_localAsset;
1271 asset.size = "888";
1272 Assets assets;
1273 assets.push_back(asset);
1274 assets.push_back(asset);
1275 bucket2.insert_or_assign("assert", asset);
1276 bucket2.insert_or_assign("asserts", assets);
1277 syncData.insData.assets.push_back(bucket2);
1278 syncData.insData.timestamp.push_back(timeVector[i - 1]);
1279 syncData.insData.hashKey.push_back({ 1 });
1280 }
1281 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1282 ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::INSERT, syncData), E_OK);
1283 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1284 }
1285
1286 /*
1287 * @tc.name: CalPrimaryKeyHash001
1288 * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is string
1289 * @tc.type: FUNC
1290 * @tc.require:
1291 * @tc.author: zhuwentao
1292 */
1293 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash001, TestSize.Level0)
1294 {
1295 /**
1296 * @tc.steps: step1. local insert one data, primary key is string
1297 * @tc.expected: OK.
1298 */
1299 std::string tableName = "user2";
1300 const std::string CREATE_LOCAL_TABLE_SQL =
1301 "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1302 "name TEXT PRIMARY KEY, age INT);";
1303 sqlite3 *db = nullptr;
1304 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1305 EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1306 ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1307 std::string name = "Local0";
1308 std::map<std::string, Type> primaryKey = {{"name", name}};
1309 std::map<std::string, CollateType> collateType = {{"name", CollateType::COLLATE_NONE}};
1310 string sql = "INSERT OR REPLACE INTO user2(name, age) VALUES ('Local" + std::to_string(0) + "', '18');";
1311 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1312 std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey, collateType);
1313 EXPECT_NE(result.size(), 0u);
1314 std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1315 /**
1316 * @tc.steps: step1. query timestamp use hashKey
1317 * @tc.expected: OK.
1318 */
1319 std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1320 sqlite3_stmt *statement = nullptr;
1321 int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1322 EXPECT_EQ(errCode, E_OK);
1323 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1324 ASSERT_EQ(errCode, E_OK);
1325 errCode = SQLiteUtils::StepWithRetry(statement, false);
1326 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1327 Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1328 LOGD("get timestamp = %" PRIu64, timestamp);
1329 errCode = E_OK;
1330 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1331 errCode = -E_NOT_FOUND;
1332 }
1333 EXPECT_EQ(errCode, E_OK);
1334 SQLiteUtils::ResetStatement(statement, true, errCode);
1335 sqlite3_close(db);
1336 }
1337
1338 /*
1339 * @tc.name: CalPrimaryKeyHash002
1340 * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is int
1341 * @tc.type: FUNC
1342 * @tc.require:
1343 * @tc.author: zhuwentao
1344 */
1345 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash002, TestSize.Level0)
1346 {
1347 /**
1348 * @tc.steps: step1. local insert one data, primary key is int
1349 * @tc.expected: OK.
1350 */
1351 std::string tableName = "user3";
1352 const std::string CREATE_LOCAL_TABLE_SQL =
1353 "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1354 "id INT PRIMARY KEY, name TEXT);";
1355 sqlite3 *db = nullptr;
1356 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1357 EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1358 ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1359 int64_t id = 1;
1360 std::map<std::string, Type> primaryKey = {{"id", id}};
1361 std::map<std::string, CollateType> collateType = {{"id", CollateType::COLLATE_NONE}};
1362 std::string sql = "INSERT OR REPLACE INTO " + tableName + " (id, name) VALUES ('" + '1' + "', 'Local" +
1363 std::to_string(0) + "');";
1364 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1365 std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey, collateType);
1366 EXPECT_NE(result.size(), 0u);
1367 std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1368 /**
1369 * @tc.steps: step1. query timestamp use hashKey
1370 * @tc.expected: OK.
1371 */
1372 std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1373 sqlite3_stmt *statement = nullptr;
1374 int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1375 EXPECT_EQ(errCode, E_OK);
1376 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1377 ASSERT_EQ(errCode, E_OK);
1378 errCode = SQLiteUtils::StepWithRetry(statement, false);
1379 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1380 Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1381 LOGD("get timestamp = %" PRIu64, timestamp);
1382 errCode = E_OK;
1383 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1384 errCode = -E_NOT_FOUND;
1385 }
1386 EXPECT_EQ(errCode, E_OK);
1387 SQLiteUtils::ResetStatement(statement, true, errCode);
1388 sqlite3_close(db);
1389 }
1390
1391 /*
1392 * @tc.name: FillCloudVersion001
1393 * @tc.desc: Test FillCloudLogAndAsset interface when opType is UPDATE_VERSION
1394 * @tc.type: FUNC
1395 * @tc.require:
1396 * @tc.author: bty
1397 */
1398 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudVersion001, TestSize.Level0)
1399 {
1400 /**
1401 * @tc.steps: step1. init data
1402 * @tc.expected: OK.
1403 */
1404 int64_t insCount = 100;
1405 int64_t photoSize = 10;
1406 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1407
1408 /**
1409 * @tc.steps: step2. FillCloudLogAndAsset which isShared is false, but extend val is empty
1410 * @tc.expected: OK.
1411 */
1412 CloudSyncData syncData(g_tableName);
1413 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1414 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1415
1416 /**
1417 * @tc.steps: step3. FillCloudLogAndAsset which isShared is true, but extend val is empty
1418 * @tc.expected: OK.
1419 */
1420 syncData.isShared = true;
1421 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1422
1423 /**
1424 * @tc.steps: step4. the extend size is not equal to the hashKey size
1425 * @tc.expected: -E_INVALID_ARGS.
1426 */
1427 VBucket extend1;
1428 extend1.insert_or_assign(CloudDbConstant::VERSION_FIELD, std::string("1"));
1429 syncData.delData.extend.push_back(extend1);
1430 syncData.updData.extend.push_back(extend1);
1431 syncData.insData.extend.push_back(extend1);
1432 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), -E_INVALID_ARGS);
1433
1434 /**
1435 * @tc.steps: step5. the extend size is equal to the hashKey size
1436 * @tc.expected: OK.
1437 */
1438 std::string hashKeyStr = "1";
1439 Bytes hashKey(hashKeyStr.begin(), hashKeyStr.end());
1440 syncData.delData.hashKey.push_back(hashKey);
1441 syncData.updData.hashKey.push_back(hashKey);
1442 syncData.insData.hashKey.push_back(hashKey);
1443 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1444
1445 /**
1446 * @tc.steps: step6. insert not contain version no effect update
1447 * @tc.expected: OK.
1448 */
1449 syncData.insData.extend[0].erase(CloudDbConstant::VERSION_FIELD);
1450 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1451
1452 /**
1453 * @tc.steps: step7. insert not contain version effect insert
1454 * @tc.expected: E_OK.
1455 */
1456 EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::INSERT_VERSION, syncData), E_OK);
1457 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1458 }
1459
1460 /*
1461 * @tc.name: PutCloudSyncVersion001
1462 * @tc.desc: Test PutCloudSyncData interface that table is share
1463 * @tc.type: FUNC
1464 * @tc.require:
1465 * @tc.author: bty
1466 */
1467 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncVersion001, TestSize.Level0)
1468 {
1469 /**
1470 * @tc.steps: step1. table type is shareTable, but downloadData is not contains version
1471 * @tc.expected: E_OK.
1472 */
1473 int64_t insCount = 10;
1474 int64_t photoSize = 10;
1475 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1476 InitLogGid(insCount);
1477 DownloadData downloadData;
1478 std::vector<OpType> opTypes = { OpType::INSERT, OpType::INSERT, OpType::DELETE, OpType::UPDATE,
1479 OpType::ONLY_UPDATE_GID, OpType::NOT_HANDLE };
1480 ConstructMultiDownloadData(insCount, downloadData, opTypes);
1481 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1482 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1483 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1484
1485 /**
1486 * @tc.steps: step2. PutCloudSyncData and check table row num
1487 * @tc.expected: E_OK.
1488 */
1489 AddVersionToDownloadData(downloadData);
1490 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1491 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1492 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1493 sqlite3 *db = nullptr;
1494 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1495 std::string querySql = "SELECT COUNT(*) FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + g_tableName +
1496 CloudDbConstant::SHARED + "_log";
1497 EXPECT_EQ(sqlite3_exec(db, querySql.c_str(),
1498 QueryCountCallback, reinterpret_cast<void *>(2L), nullptr), SQLITE_OK);
1499 sqlite3_close(db);
1500 }
1501
1502 /*
1503 * @tc.name: PutCloudSyncVersion002
1504 * @tc.desc: Test PutCloudSyncData interface that download data is not contains version
1505 * @tc.type: FUNC
1506 * @tc.require:
1507 * @tc.author: bty
1508 */
1509 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncVersion002, TestSize.Level0)
1510 {
1511 /**
1512 * @tc.steps: step1. table type is shareTable, but downloadData is not contains version
1513 * @tc.expected: E_OK.
1514 */
1515 int64_t insCount = 10;
1516 int64_t photoSize = 10;
1517 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1518 InitLogGid(insCount);
1519 DownloadData downloadData;
1520 std::vector<OpType> opTypes = { OpType::INSERT, OpType::INSERT, OpType::INSERT };
1521 ConstructMultiDownloadData(insCount, downloadData, opTypes);
1522 AddVersionToDownloadData(downloadData);
1523 AddCloudOwnerToDownloadData(downloadData);
1524 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1525 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1526
1527 /**
1528 * @tc.steps: step2. test opType of DELETE,UPDATE_TIMESTAMP,and CLEAR_GID without version field
1529 * @tc.expected: E_OK.
1530 */
1531 downloadData.opType = { OpType::DELETE, OpType::UPDATE_TIMESTAMP, OpType::CLEAR_GID };
1532 for (size_t i = 0; i < downloadData.data.size(); i++) {
1533 downloadData.data[i].erase(CloudDbConstant::VERSION_FIELD);
1534 }
1535 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1536 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1537 }
1538
1539 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize.Level0)
1540 {
1541 /**
1542 * @tc.steps: step1. both gid and hashKey are empty
1543 * @tc.expected: -E_INVALID_ARGS.
1544 */
1545 int64_t insCount = 10;
1546 int64_t photoSize = 10;
1547 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1548 UpdateLogGidAndHashKey(insCount);
1549 VBucket assets;
1550 std::string gid;
1551 Bytes hashKey;
1552 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1553 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_INVALID_ARGS);
1554 EXPECT_EQ(assets.size(), 0u);
1555
1556 /**
1557 * @tc.steps: step2. gid is empty, but hashKey is 2
1558 * @tc.expected: E_OK.
1559 */
1560 Asset asset = g_localAsset;
1561 asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1562 UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
1563 std::string pk = "2";
1564 hashKey.assign(pk.begin(), pk.end());
1565 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1566 CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::UPDATE));
1567
1568 /**
1569 * @tc.steps: step3. gid is empty, but hashKey out of range
1570 * @tc.expected: -E_NOT_FOUND.
1571 */
1572 assets = {};
1573 pk = "11";
1574 hashKey.assign(pk.begin(), pk.end());
1575 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1576 EXPECT_EQ(assets.size(), 0u);
1577
1578 /**
1579 * @tc.steps: step4. hashKey is empty, but gid is 4
1580 * @tc.expected: E_OK.
1581 */
1582 gid = "2";
1583 pk = {};
1584 assets = {};
1585 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1586 CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::UPDATE));
1587
1588 /**
1589 * @tc.steps: step5. hashKey is empty, but gid is out of range
1590 * @tc.expected: -E_NOT_FOUND.
1591 */
1592 gid = "11";
1593 assets = {};
1594 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1595 EXPECT_EQ(assets.size(), 0u);
1596 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1597 }
1598
1599 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset002, TestSize.Level0)
1600 {
1601 /**
1602 * @tc.steps: step1. hashKey is 2, or gid is 4
1603 * @tc.expected: E_OK.
1604 */
1605 int64_t insCount = 10;
1606 int64_t photoSize = 10;
1607 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1608 UpdateLogGidAndHashKey(insCount);
1609 VBucket assets;
1610 Bytes hashKey;
1611 Asset asset = g_localAsset;
1612 asset.status = static_cast<uint32_t>(AssetStatus::INSERT);
1613 UpdateLocalAsset(g_tableName, asset, 4L); // 4 is rowid
1614 std::string gid = "4";
1615 std::string pk = "2";
1616 hashKey.assign(pk.begin(), pk.end());
1617 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1618 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1619 CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::INSERT));
1620
1621 /**
1622 * @tc.steps: step2. hashKey is 1, or gid is 11
1623 * @tc.expected: E_OK.
1624 */
1625 assets = {};
1626 gid = "11";
1627 pk = "1";
1628 hashKey.assign(pk.begin(), pk.end());
1629 EXPECT_EQ(
1630 g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_CLOUD_GID_MISMATCH);
1631 CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::NORMAL));
1632
1633 /**
1634 * @tc.steps: step3. hashKey is 12, or gid is 11
1635 * @tc.expected: -E_NOT_FOUND.
1636 */
1637 assets = {};
1638 pk = "12";
1639 hashKey.assign(pk.begin(), pk.end());
1640 EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1641 EXPECT_EQ(assets.size(), 0u);
1642 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1643 }
1644
1645 /**
1646 * @tc.name: GetCloudData007
1647 * @tc.desc: Test get cloud data which contains abnormal status asset
1648 * @tc.type: FUNC
1649 * @tc.require:
1650 * @tc.author: bty
1651 */
1652 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData007, TestSize.Level0)
1653 {
1654 /**
1655 * @tc.steps:step1. Init data and set asset status to abnormal
1656 * @tc.expected: step1. return ok.
1657 */
1658 CreateLogTable(g_tableName);
1659 int64_t insCount = 10;
1660 int64_t photoSize = 1024 * 100;
1661 InitLogData(insCount * 3, insCount * 3, 1, insCount, g_logTblName); // 3 is multiple
1662 CreateAndInitUserTable(insCount, photoSize, g_localAsset); // 2 is insert,update type data
1663 Asset asset = g_localAsset;
1664 asset.status = static_cast<uint32_t>(AssetStatus::ABNORMAL);
1665 insCount = 50;
1666 CreateAndInitUserTable(insCount, photoSize, asset);
1667 SetDbSchema(g_tableSchema);
1668
1669 /**
1670 * @tc.steps:step2. Get all cloud data at once
1671 * @tc.expected: step2. return E_OK.
1672 */
1673 ContinueToken token = nullptr;
1674 CloudSyncData cloudSyncData;
1675 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1676 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
1677 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1678 }
1679
1680 /**
1681 * @tc.name: ContainAssetsTable001
1682 * @tc.desc: Test cloud schema contain asset table
1683 * @tc.type: FUNC
1684 * @tc.require:
1685 * @tc.author: zqq
1686 */
1687 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, ContainAssetsTable001, TestSize.Level0)
1688 {
1689 ASSERT_NE(g_storageProxy, nullptr);
1690 EXPECT_FALSE(g_storageProxy->IsExistTableContainAssets());
1691 ASSERT_NE(g_cloudStore, nullptr);
1692 DataBaseSchema dataBaseSchema;
1693 dataBaseSchema.tables.push_back(g_tableSchema);
1694 EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK);
1695 EXPECT_FALSE(g_storageProxy->IsExistTableContainAssets());
1696 int64_t insCount = 100;
1697 int64_t photoSize = 10;
1698 InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1699 EXPECT_TRUE(g_storageProxy->IsExistTableContainAssets());
1700 }
1701 }
1702 #endif // RELATIONAL_STORE
1703