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 "distributeddb_tools_unit_test.h"
19 #include "relational_store_manager.h"
20 #include "distributeddb_data_generate_unit_test.h"
21 #include "relational_sync_able_storage.h"
22 #include "relational_store_instance.h"
23 #include "sqlite_relational_store.h"
24 #include "log_table_manager_factory.h"
25 #include "cloud_db_constant.h"
26 #include "runtime_config.h"
27 #include "virtual_cloud_data_translate.h"
28
29 using namespace testing::ext;
30 using namespace DistributedDB;
31 using namespace DistributedDBUnitTest;
32 using namespace std;
33
34 namespace {
35 string g_storeID = "Relational_Store_ID";
36 string g_tableName = "cloudData";
37 string g_logTblName;
38 string g_testDir;
39 string g_storePath;
40 const Timestamp g_startTime = 100000;
41 const int g_deleteFlag = 0x01;
42 const int g_localFlag = 0x02;
43 const std::string CREATE_LOCAL_TABLE_SQL =
44 "CREATE TABLE IF NOT EXISTS " + g_tableName + "(" \
45 "name TEXT ," \
46 "height REAL ," \
47 "married INT ," \
48 "photo BLOB ," \
49 "assert BLOB," \
50 "asserts BLOB," \
51 "age INT);";
52 const std::vector<Field> g_cloudFiled = {
53 {"name", TYPE_INDEX<std::string>}, {"age", TYPE_INDEX<int64_t>},
54 {"height", TYPE_INDEX<double>}, {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>},
55 {"assert", TYPE_INDEX<Asset>}, {"asserts", TYPE_INDEX<Assets>}
56 };
57 const Asset g_localAsset = {
58 .version = 1, .name = "Phone", .uri = "/local/sync", .modifyTime = "123456", .createTime = "",
59 .size = "256", .hash = " ", .flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE),
60 .status = static_cast<uint32_t>(AssetStatus::NORMAL), .timestamp = 0L
61 };
62 DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
63 RelationalStoreDelegate *g_delegate = nullptr;
64 IRelationalStore *g_store = nullptr;
65 ICloudSyncStorageInterface *g_cloudStore = nullptr;
66 std::shared_ptr<StorageProxy> g_storageProxy = nullptr;
67 TableSchema g_tableSchema;
68
CreateDB()69 void CreateDB()
70 {
71 sqlite3 *db = nullptr;
72 int errCode = sqlite3_open(g_storePath.c_str(), &db);
73 if (errCode != SQLITE_OK) {
74 LOGE("open db failed:%d", errCode);
75 sqlite3_close(db);
76 return;
77 }
78
79 const string sql =
80 "PRAGMA journal_mode=WAL;";
81 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
82 sqlite3_close(db);
83 }
84
CreateLogTable()85 void CreateLogTable()
86 {
87 TableInfo table;
88 table.SetTableName(g_tableName);
89 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
90 sqlite3 *db = nullptr;
91 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
92 auto tableManager =
93 LogTableManagerFactory::GetTableManager(DistributedTableMode::COLLABORATION, TableSyncType::CLOUD_COOPERATION);
94 int errCode = tableManager->CreateRelationalLogTable(db, table);
95 EXPECT_EQ(errCode, E_OK);
96 sqlite3_close(db);
97 }
98
CreateAndInitUserTable(int64_t count,int64_t photoSize)99 void CreateAndInitUserTable(int64_t count, int64_t photoSize)
100 {
101 sqlite3 *db = nullptr;
102 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
103
104 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
105 std::string photo(photoSize, 'v');
106 std::vector<uint8_t> assetBlob;
107 std::vector<uint8_t> assetsBlob;
108 Asset asset = g_localAsset;
109 int id = 0;
110 Assets assets;
111 asset.name = g_localAsset.name + std::to_string(id++);
112 assets.push_back(asset);
113 asset.name = g_localAsset.name + std::to_string(id++);
114 assets.push_back(asset);
115 int errCode;
116 ASSERT_EQ(RuntimeContext::GetInstance()->AssetToBlob(g_localAsset, assetBlob), E_OK);
117 ASSERT_EQ(RuntimeContext::GetInstance()->AssetsToBlob(assets, assetsBlob), E_OK);
118 for (int i = 1; i <= count; ++i) {
119 string sql = "INSERT OR REPLACE INTO " + g_tableName +
120 " (name, height, married, photo, assert, asserts, age) VALUES ('Tom" + std::to_string(i) +
121 "', '175.8', '0', '" + photo + "', ? , ?, '18');";
122 sqlite3_stmt *stmt = nullptr;
123 ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
124 if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) != E_OK) { // 1 is asset index
125 SQLiteUtils::ResetStatement(stmt, true, errCode);
126 }
127 if (SQLiteUtils::BindBlobToStatement(stmt, 2, assetsBlob, false) != E_OK) { // 2 is index of asserts
128 SQLiteUtils::ResetStatement(stmt, true, errCode);
129 }
130 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
131 SQLiteUtils::ResetStatement(stmt, true, errCode);
132 }
133 sqlite3_close(db);
134 }
135
InitLogData(int64_t insCount,int64_t updCount,int64_t delCount,int64_t excludeCount)136 void InitLogData(int64_t insCount, int64_t updCount, int64_t delCount, int64_t excludeCount)
137 {
138 sqlite3 *db = nullptr;
139 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
140 std::string flag;
141 std::string cloudGid;
142 for (int64_t i = 1; i <= insCount + updCount + delCount + excludeCount; ++i) {
143 if (i <= insCount) {
144 flag = std::to_string(g_localFlag);
145 cloudGid = "''";
146 } else if (i > insCount && i <= insCount + updCount) {
147 flag = std::to_string(g_localFlag);
148 cloudGid = "'" + g_storeID + std::to_string(i) + "'";
149 } else if (i > (insCount + updCount) && i <= (insCount + updCount + delCount)) {
150 flag = std::to_string(g_localFlag | g_deleteFlag);
151 cloudGid = "'" + g_storeID + std::to_string(i) + "'";
152 } else {
153 flag = std::to_string(g_localFlag | g_deleteFlag);
154 cloudGid = "''";
155 }
156 string sql = "INSERT OR REPLACE INTO " + g_logTblName +
157 " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cloud_gid)" +
158 " VALUES ('" + std::to_string(i) + "', '', '', '" + std::to_string(g_startTime + i) + "', '" +
159 std::to_string(g_startTime + i) + "','" + flag + "','" + std::to_string(i) + "', " + cloudGid + ");";
160 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
161 }
162 sqlite3_close(db);
163 }
164
InitLogGid(int64_t count)165 void InitLogGid(int64_t count)
166 {
167 sqlite3 *db = nullptr;
168 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
169 for (int i = 1; i <= count; i++) {
170 string sql = "update " + g_logTblName + " set cloud_gid = '" + std::to_string(i) +
171 "' where data_key = " + std::to_string(i);
172 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
173 }
174 sqlite3_close(db);
175 }
176
ConstructMultiDownloadData(int64_t count,DownloadData & downloadData)177 void ConstructMultiDownloadData(int64_t count, DownloadData &downloadData)
178 {
179 for (int i = 1; i <= 5; i++) { // 5 is random num
180 Asset asset = g_localAsset;
181 Assets assets;
182 VBucket vBucket;
183 if (i <= 2) { // 2 is deleted or insert type
184 asset.flag = static_cast<uint32_t>(i == 1 ? AssetOpType::DELETE : AssetOpType::INSERT);
185 vBucket[CloudDbConstant::GID_FIELD] = (i == 1 ? std::to_string(i) : std::to_string(count + i));
186 } else {
187 asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
188 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
189 }
190 vBucket["assert"] = asset;
191 asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
192 assets.push_back(asset);
193 asset.flag = static_cast<uint32_t>(AssetOpType::INSERT);
194 assets.push_back(asset);
195 asset.flag = static_cast<uint32_t>(AssetOpType::DELETE);
196 assets.push_back(asset);
197 asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
198 assets.push_back(asset);
199 vBucket["asserts"] = assets;
200 std::string name = "lisi" + std::to_string(i);
201 vBucket["name"] = name;
202 vBucket["age"] = (int64_t)i;
203 int64_t mTime = 12345679L + i;
204 vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
205 vBucket[CloudDbConstant::CREATE_FIELD] = mTime;
206 downloadData.data.push_back(vBucket);
207 }
208 downloadData.opType = { OpType::DELETE, OpType::INSERT, OpType::UPDATE,
209 OpType::UPDATE, OpType::NOT_HANDLE };
210 }
211
SetDbSchema(const TableSchema & tableSchema)212 void SetDbSchema(const TableSchema &tableSchema)
213 {
214 DataBaseSchema dataBaseSchema;
215 dataBaseSchema.tables.push_back(tableSchema);
216 EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK);
217 }
218
InitUserDataForAssetTest(int64_t insCount,int64_t photoSize)219 void InitUserDataForAssetTest(int64_t insCount, int64_t photoSize)
220 {
221 sqlite3 *db = nullptr;
222 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
223 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
224 sqlite3_close(db);
225 EXPECT_EQ(g_delegate->CreateDistributedTable(g_tableName, DistributedDB::CLOUD_COOPERATION), OK);
226 CreateAndInitUserTable(insCount, photoSize);
227 SetDbSchema(g_tableSchema);
228 }
229
QueryCountCallback(void * data,int count,char ** colValue,char ** colName)230 int QueryCountCallback(void *data, int count, char **colValue, char **colName)
231 {
232 if (count != 1) {
233 return 0;
234 }
235 auto expectCount = reinterpret_cast<int64_t>(data);
236 EXPECT_EQ(strtol(colValue[0], nullptr, 10), expectCount); // 10: decimal
237 return 0;
238 }
239
fillCloudAssetTest(int64_t count,AssetStatus statusType,bool isDownloadSuccess)240 void fillCloudAssetTest(int64_t count, AssetStatus statusType, bool isDownloadSuccess)
241 {
242 VBucket vBucket;
243 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(1);
244 for (int i = 0; i < 4; i ++) { // 4 is AssetStatus Num
245 Asset asset = g_localAsset;
246 asset.flag = i;
247 asset.status = static_cast<uint32_t>(statusType);
248 asset.timestamp = g_startTime;
249 Assets assets;
250 for (int j = 0; j < 4; j++) { // 4 is AssetStatus Num
251 Asset temp = g_localAsset;
252 temp.flag = j;
253 temp.status = static_cast<uint32_t>(statusType);
254 temp.timestamp = g_startTime + j;
255 assets.push_back(temp);
256 }
257 vBucket["assert"] = asset;
258 vBucket["asserts"] = assets;
259 ASSERT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
260 ASSERT_EQ(g_storageProxy->FillCloudAssetForDownload(g_tableName, vBucket, isDownloadSuccess), E_OK);
261 ASSERT_EQ(g_storageProxy->Commit(), E_OK);
262 }
263 }
264
UpdateLocalAsset(const std::string & tableName,Asset & asset,int64_t rowid)265 void UpdateLocalAsset(const std::string &tableName, Asset &asset, int64_t rowid)
266 {
267 sqlite3 *db = nullptr;
268 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
269 string sql = "UPDATE " + tableName + " SET assert = ? where rowid = '" + std::to_string(rowid) + "';";
270 std::vector<uint8_t> assetBlob;
271 int errCode;
272 RuntimeContext::GetInstance()->AssetToBlob(asset, assetBlob);
273 sqlite3_stmt *stmt = nullptr;
274 ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
275 if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) == E_OK) {
276 EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
277 }
278 SQLiteUtils::ResetStatement(stmt, true, errCode);
279 sqlite3_close(db);
280 }
281
InitStoreProp(const std::string & storePath,const std::string & appId,const std::string & userId,RelationalDBProperties & properties)282 void InitStoreProp(const std::string &storePath, const std::string &appId, const std::string &userId,
283 RelationalDBProperties &properties)
284 {
285 properties.SetStringProp(RelationalDBProperties::DATA_DIR, storePath);
286 properties.SetStringProp(RelationalDBProperties::APP_ID, appId);
287 properties.SetStringProp(RelationalDBProperties::USER_ID, userId);
288 properties.SetStringProp(RelationalDBProperties::STORE_ID, g_storeID);
289 std::string identifier = userId + "-" + appId + "-" + g_storeID;
290 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
291 properties.SetStringProp(RelationalDBProperties::IDENTIFIER_DATA, hashIdentifier);
292 }
293
GetRelationalStore()294 const RelationalSyncAbleStorage *GetRelationalStore()
295 {
296 RelationalDBProperties properties;
297 InitStoreProp(g_storePath, APP_ID, USER_ID, properties);
298 int errCode = E_OK;
299 g_store = RelationalStoreInstance::GetDataBase(properties, errCode);
300 if (g_store == nullptr) {
301 LOGE("Get db failed:%d", errCode);
302 return nullptr;
303 }
304 return static_cast<SQLiteRelationalStore *>(g_store)->GetStorageEngine();
305 }
306
GetStorageProxy(ICloudSyncStorageInterface * store)307 std::shared_ptr<StorageProxy> GetStorageProxy(ICloudSyncStorageInterface *store)
308 {
309 return StorageProxy::GetCloudDb(store);
310 }
311
312 class DistributedDBRelationalCloudSyncableStorageTest : public testing::Test {
313 public:
314 static void SetUpTestCase(void);
315 static void TearDownTestCase(void);
316 void SetUp();
317 void TearDown();
318 };
319
320
SetUpTestCase(void)321 void DistributedDBRelationalCloudSyncableStorageTest::SetUpTestCase(void)
322 {
323 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
324 g_storePath = g_testDir + "/cloudDataTest.db";
325 g_logTblName = DBConstant::RELATIONAL_PREFIX + g_tableName + "_log";
326 LOGI("The test db is:%s", g_testDir.c_str());
327 RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
328 g_tableSchema.name = g_tableName;
329 g_tableSchema.fields = g_cloudFiled;
330 }
331
TearDownTestCase(void)332 void DistributedDBRelationalCloudSyncableStorageTest::TearDownTestCase(void)
333 {}
334
SetUp(void)335 void DistributedDBRelationalCloudSyncableStorageTest::SetUp(void)
336 {
337 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
338 LOGE("rm test db files error.");
339 }
340 DistributedDBToolsUnitTest::PrintTestCaseInfo();
341 LOGD("Test dir is %s", g_testDir.c_str());
342 CreateDB();
343 ASSERT_EQ(g_mgr.OpenStore(g_storePath, g_storeID, RelationalStoreDelegate::Option {}, g_delegate), DBStatus::OK);
344 ASSERT_NE(g_delegate, nullptr);
345 g_cloudStore = (ICloudSyncStorageInterface *) GetRelationalStore();
346 ASSERT_NE(g_cloudStore, nullptr);
347 g_storageProxy = GetStorageProxy(g_cloudStore);
348 ASSERT_NE(g_storageProxy, nullptr);
349 }
350
TearDown(void)351 void DistributedDBRelationalCloudSyncableStorageTest::TearDown(void)
352 {
353 RefObject::DecObjRef(g_store);
354 if (g_delegate != nullptr) {
355 EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK);
356 g_delegate = nullptr;
357 }
358 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
359 LOGE("rm test db files error.");
360 }
361 }
362
363 /**
364 * @tc.name: MetaDataTest001
365 * @tc.desc: Test PutMetaData and GetMetaData from ICloudSyncStorageInterface impl class
366 * @tc.type: FUNC
367 * @tc.require:
368 * @tc.author: bty
369 */
370 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest001, TestSize.Level1)
371 {
372 EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_2), E_OK);
373 EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_3), E_OK);
374
375 Value value;
376 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
377 EXPECT_EQ(value, VALUE_3);
378 }
379
380 /**
381 * @tc.name: MetaDataTest002
382 * @tc.desc: The GetMetaData supports key sizes up to 1024
383 * @tc.type: FUNC
384 * @tc.require:
385 * @tc.author: bty
386 */
387 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest002, TestSize.Level1)
388 {
389 const string str(DBConstant::MAX_KEY_SIZE, 'k');
390 const Key key(str.begin(), str.end());
391 EXPECT_EQ(g_cloudStore->PutMetaData(key, VALUE_2), E_OK);
392 Value value;
393 EXPECT_EQ(g_cloudStore->GetMetaData(key, value), E_OK);
394 EXPECT_EQ(value, VALUE_2);
395
396 const string maxStr(DBConstant::MAX_KEY_SIZE + 1, 'k');
397 const Key maxKey(maxStr.begin(), maxStr.end());
398 EXPECT_EQ(g_cloudStore->PutMetaData(maxKey, VALUE_3), E_OK);
399 EXPECT_EQ(g_cloudStore->GetMetaData(maxKey, value), -E_INVALID_ARGS);
400 }
401
402 /**
403 * @tc.name: TransactionTest001
404 * @tc.desc: No write transaction in the current store, meta interface can called
405 * @tc.type: FUNC
406 * @tc.require:
407 * @tc.author: bty
408 */
409 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest001, TestSize.Level1)
410 {
411 /**
412 * @tc.steps: allow get or put meta in read transaction
413 * @tc.expected: Succeed, return OK.
414 */
415 EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
416 g_cloudStore->PutMetaData(KEY_1, VALUE_1);
417 EXPECT_EQ(g_cloudStore->Rollback(), E_OK);
418 g_cloudStore->PutMetaData(KEY_2, VALUE_2);
419
420 Value value;
421 EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
422 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
423 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_2, value), E_OK);
424 g_cloudStore->PutMetaData(KEY_3, VALUE_3);
425 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
426 EXPECT_EQ(g_cloudStore->Commit(), E_OK);
427 EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
428 }
429
430 /**
431 * @tc.name: TransactionTest002
432 * @tc.desc: Test transaction interface from StorageProxy
433 * @tc.type: FUNC
434 * @tc.require:
435 * @tc.author: bty
436 */
437 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest002, TestSize.Level1)
438 {
439 Timestamp cloudTime = 666888;
440 Timestamp localTime;
441 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
442
443 /**
444 * @tc.steps: allow get or put waterMark in read transaction
445 * @tc.expected: Succeed, return OK.
446 */
447 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
448 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
449 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
450 EXPECT_EQ(cloudTime, localTime);
451 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
452 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
453
454 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
455 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
456 cloudTime = 999666;
457 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
458 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
459 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
460 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
461 EXPECT_EQ(cloudTime, localTime);
462
463 /**
464 * @tc.steps: not allow get or put waterMark in write transaction
465 * @tc.expected: return -E_BUSY.
466 */
467 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
468 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), -E_BUSY);
469 EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), -E_BUSY);
470 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
471 EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
472 }
473
474 /**
475 * @tc.name: TransactionTest003
476 * @tc.desc: Repeatedly call transaction interface from StorageProxy
477 * @tc.type: FUNC
478 * @tc.require:
479 * @tc.author: bty
480 */
481 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest003, TestSize.Level1)
482 {
483 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
484
485 /**
486 * @tc.steps: Repeated start transactions is not allowed
487 * @tc.expected: return -E_TRANSACT_STATE.
488 */
489 EXPECT_EQ(g_storageProxy->StartTransaction(), -E_TRANSACT_STATE);
490
491 /**
492 * @tc.steps: Repeated commit is not allowed
493 * @tc.expected: return -E_INVALID_DB.
494 */
495 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
496 EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
497
498 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
499
500 /**
501 * @tc.steps: Repeated Rollback is not allowed
502 * @tc.expected: return -E_INVALID_DB.
503 */
504 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
505 EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
506 }
507
508 /**
509 * @tc.name: TransactionTest004
510 * @tc.desc: Call transaction after close storageProxy
511 * @tc.type: FUNC
512 * @tc.require:
513 * @tc.author: bty
514 */
515 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest004, TestSize.Level1)
516 {
517 /**
518 * @tc.steps: transaction is not allowed after closing the proxy
519 * @tc.expected: return -E_INVALID_DB.
520 */
521 EXPECT_EQ(g_storageProxy->Close(), E_OK);
522 EXPECT_EQ(g_storageProxy->StartTransaction(), -E_INVALID_DB);
523 EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
524 EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
525
526 g_storageProxy = GetStorageProxy(g_cloudStore);
527 ASSERT_NE(g_storageProxy, nullptr);
528 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
529
530 /**
531 * @tc.steps: close proxy is not allowed before the transaction has been commit or rollback
532 * @tc.expected: return -E_BUSY.
533 */
534 EXPECT_EQ(g_storageProxy->Close(), -E_BUSY);
535 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
536 EXPECT_EQ(g_storageProxy->Close(), E_OK);
537 }
538
539 /**
540 * @tc.name: GetUploadCount001
541 * @tc.desc: Test getUploadCount by ICloudSyncStorageInterface
542 * @tc.type: FUNC
543 * @tc.require:
544 * @tc.author: bty
545 */
546 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount001, TestSize.Level1)
547 {
548 /**
549 * @tc.steps: Table does not exist
550 * @tc.expected: return -SQLITE_ERROR.
551 */
552 int64_t resCount = 0;
553 EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, g_startTime, false, resCount), -SQLITE_ERROR);
554
555 CreateLogTable();
556 int64_t insCount = 100;
557 InitLogData(insCount, insCount, insCount, insCount);
558 EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
559 EXPECT_EQ(resCount, insCount + insCount + insCount);
560
561 /**
562 * @tc.steps: There are no matching data anymore
563 * @tc.expected: count is 0 and return E_OK.
564 */
565 Timestamp invalidTime = g_startTime + g_startTime;
566 EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, invalidTime, false, resCount), E_OK);
567 EXPECT_EQ(resCount, 0);
568 }
569
570 /**
571 * @tc.name: GetUploadCount002
572 * @tc.desc: Test getUploadCount by storageProxy
573 * @tc.type: FUNC
574 * @tc.require:
575 * @tc.author: bty
576 */
577 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount002, TestSize.Level1)
578 {
579 CreateLogTable();
580 int64_t insCount = 100;
581 InitLogData(insCount, insCount, 0, insCount);
582 int64_t resCount = 0;
583
584 /**
585 * @tc.steps: GetUploadCount must be called under transaction
586 * @tc.expected: return -E_TRANSACT_STATE.
587 */
588 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
589
590 int timeOffset = 30;
591 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
592 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
593 EXPECT_EQ(resCount, insCount + insCount - timeOffset);
594 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
595
596 /**
597 * @tc.steps: GetUploadCount also can be called under write transaction
598 * @tc.expected: return E_OK.
599 */
600 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
601 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
602 EXPECT_EQ(resCount, insCount + insCount - timeOffset);
603 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
604 }
605
606 /**
607 * @tc.name: GetUploadCount003
608 * @tc.desc: Test getUploadCount exclude condition of (deleteFlag and cloud_gid is '')
609 * @tc.type: FUNC
610 * @tc.require:
611 * @tc.author: bty
612 */
613 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount003, TestSize.Level1)
614 {
615 CreateLogTable();
616 int64_t insCount = 100;
617 InitLogData(0, 0, insCount, insCount);
618 int64_t resCount = 0;
619
620 /**
621 * @tc.steps: GetUploadCount must be called under transaction
622 * @tc.expected: return -E_TRANSACT_STATE.
623 */
624 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
625
626 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
627 EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
628 EXPECT_EQ(resCount, insCount);
629 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
630 }
631
632 /**
633 * @tc.name: FillCloudGid001
634 * @tc.desc: FillCloudGid with invalid parm
635 * @tc.type: FUNC
636 * @tc.require:
637 * @tc.author: bty
638 */
639 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid001, TestSize.Level1)
640 {
641 CreateLogTable();
642 int64_t insCount = 100;
643 InitLogData(insCount, 0, insCount, insCount);
644 CloudSyncData syncData;
645
646 /**
647 * @tc.steps: rowid set is empty
648 * @tc.expected: return -E_INVALID_ARGS.
649 */
650 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
651 syncData.insData.rowid.push_back(1);
652 syncData.insData.rowid.push_back(2); // 2 is random id
653
654 /**
655 * @tc.steps: insData set is empty
656 * @tc.expected: return -E_INVALID_ARGS.
657 */
658 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
659 VBucket bucket1;
660 bucket1.insert_or_assign(g_tableName, g_tableName);
661 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, 1L);
662 syncData.insData.extend.push_back(bucket1);
663
664 /**
665 * @tc.steps: the size of rowid and insData is not equal
666 * @tc.expected: return -E_INVALID_ARGS.
667 */
668 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
669
670 /**
671 * @tc.steps: table name is empty
672 * @tc.expected: return -SQLITE_ERROR.
673 */
674 VBucket bucket2;
675 bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, 2L); // 2L is random field
676 syncData.insData.extend.push_back(bucket2);
677 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -SQLITE_ERROR);
678
679 /**
680 * @tc.steps: the field type does not match
681 * @tc.expected: return -E_INVALID_DATA.
682 */
683 syncData.tableName = g_tableName;
684 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_DATA);
685
686 /**
687 * @tc.steps: missing field GID_FIELD
688 * @tc.expected: return -E_INVALID_ARGS.
689 */
690 syncData.insData.extend.clear();
691 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("1"));
692 bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, std::string("2"));
693 syncData.insData.extend.push_back(bucket1);
694 syncData.insData.extend.push_back(bucket2);
695 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
696
697 syncData.insData.extend.pop_back();
698 bucket2.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("2"));
699 syncData.insData.extend.push_back(bucket2);
700 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), E_OK);
701
702 /**
703 * @tc.steps: table name is not exists
704 * @tc.expected: return -SQLITE_ERROR.
705 */
706 syncData.tableName = "noneTable";
707 EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -SQLITE_ERROR);
708 }
709
710 /**
711 * @tc.name: FillCloudGid002
712 * @tc.desc: Test whether the num of gid after fill are correct
713 * @tc.type: FUNC
714 * @tc.require:
715 * @tc.author: bty
716 */
717 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid002, TestSize.Level1)
718 {
719 CreateLogTable();
720 int64_t insCount = 100;
721 int64_t updCount = 50;
722 int64_t delCount = 50;
723 InitLogData(insCount, updCount, delCount, insCount);
724
725 CloudSyncData syncData(g_tableName);
726 for (int64_t i = 1; i <= 3 * insCount; ++i) { // 3 is insert,update and delete type data
727 syncData.insData.rowid.push_back(i);
728 VBucket bucket1;
729 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(g_startTime + i));
730 syncData.insData.extend.push_back(bucket1);
731 }
732 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
733 EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), E_OK);
734 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
735
736 sqlite3 *db = nullptr;
737 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
738 std::string querySql = "SELECT COUNT(*) FROM " + g_logTblName + " WHERE cloud_gid in (";
739 for (int64_t i = 1; i <= (insCount + updCount + delCount); ++i) {
740 querySql += "'" + std::to_string(g_startTime + i) + "',";
741 }
742 querySql.pop_back();
743 querySql += ");";
744 EXPECT_EQ(sqlite3_exec(db, querySql.c_str(),
745 QueryCountCallback, reinterpret_cast<void *>(insCount + updCount + delCount), nullptr), SQLITE_OK);
746 sqlite3_close(db);
747 }
748
749 /**
750 * @tc.name: FillCloudGid003
751 * @tc.desc: Test FillCloudGid after in write transaction
752 * @tc.type: FUNC
753 * @tc.require:
754 * @tc.author: bty
755 */
756 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid003, TestSize.Level1)
757 {
758 CreateLogTable();
759 int64_t insCount = 10;
760 InitLogData(insCount, insCount, insCount, insCount);
761 CloudSyncData syncData(g_tableName);
762 for (int64_t i = 1; i <= (insCount + insCount + insCount); ++i) {
763 syncData.insData.rowid.push_back(i);
764 VBucket bucket1;
765 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(g_startTime + i));
766 syncData.insData.extend.push_back(bucket1);
767 }
768
769 /**
770 * @tc.steps: FillCloudGid is not allowed after starting write transaction
771 * @tc.expected: return -E_BUSY.
772 */
773 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
774 EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), -E_BUSY);
775 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
776 }
777
778 /**
779 * @tc.name: FillCloudGid004
780 * @tc.desc: Test FillCloudGid when gid is empty
781 * @tc.type: FUNC
782 * @tc.require:
783 * @tc.author: bty
784 */
785 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid004, TestSize.Level1)
786 {
787 CreateLogTable();
788 int64_t insCount = 2;
789 InitLogData(insCount, insCount, insCount, insCount);
790 CloudSyncData syncData(g_tableName);
791 syncData.insData.rowid.push_back(0);
792 VBucket bucket1;
793 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string(""));
794 syncData.insData.extend.push_back(bucket1);
795
796 /**
797 * @tc.steps: FillCloudGid is not allowed when gid is empty
798 * @tc.expected: return -E_CLOUD_ERROR.
799 */
800 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
801 EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), -E_CLOUD_ERROR);
802 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
803 }
804
805 /**
806 * @tc.name: GetCloudData001
807 * @tc.desc: Test GetCloudData,whether the result count and type of data are correct
808 * @tc.type: FUNC
809 * @tc.require:
810 * @tc.author: bty
811 */
812 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData001, TestSize.Level1)
813 {
814 CreateLogTable();
815 int64_t insCount = 100;
816 int64_t updCount = 50;
817 int64_t delCount = 25;
818 int64_t photoSize = 10;
819 InitLogData(insCount, updCount, delCount, insCount);
820 CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
821
822 ContinueToken token = nullptr;
823 CloudSyncData cloudSyncData;
824 SetDbSchema(g_tableSchema);
825
826 /**
827 * @tc.steps: There is currently no handle under the transaction
828 * @tc.expected: return -E_INVALID_DB.
829 */
830 int timeOffset = 10;
831 EXPECT_EQ(g_cloudStore->GetCloudData(g_tableSchema, g_startTime + timeOffset, token, cloudSyncData), -E_INVALID_DB);
832
833 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
834 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData), E_OK);
835 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
836 EXPECT_EQ(cloudSyncData.insData.record.size() + cloudSyncData.updData.record.size() +
837 cloudSyncData.delData.record.size(), static_cast<uint64_t>(insCount + updCount + delCount - timeOffset));
838 ASSERT_EQ(cloudSyncData.insData.record.size(), static_cast<uint64_t>(insCount - timeOffset));
839 ASSERT_EQ(cloudSyncData.updData.record.size(), static_cast<uint64_t>(updCount));
840 ASSERT_EQ(cloudSyncData.delData.record.size(), static_cast<uint64_t>(delCount));
841
842 EXPECT_EQ(cloudSyncData.insData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
843 EXPECT_NE(cloudSyncData.updData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
844 EXPECT_NE(cloudSyncData.delData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
845
846
847 /**
848 * @tc.steps: GetCloudData also can be called under write transaction
849 * @tc.expected: return E_OK.
850 */
851 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
852 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData), E_OK);
853 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
854 }
855
856 /**
857 * @tc.name: GetCloudData002
858 * @tc.desc: The maximum return data size of GetCloudData is less than 8M
859 * @tc.type: FUNC
860 * @tc.require:
861 * @tc.author: bty
862 */
863 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData002, TestSize.Level1)
864 {
865 CreateLogTable();
866 int64_t insCount = 1024;
867 int64_t photoSize = 512 * 3;
868 InitLogData(insCount, insCount, insCount, insCount);
869 CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
870
871
872 /**
873 * @tc.steps: GetCloudData has not finished querying yet.
874 * @tc.expected: return -E_UNFINISHED.
875 */
876 SetDbSchema(g_tableSchema);
877 ContinueToken token = nullptr;
878 CloudSyncData cloudSyncData1;
879 int timeOffset = 10;
880 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
881 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData1),
882 -E_UNFINISHED);
883 EXPECT_LT(cloudSyncData1.insData.record.size() + cloudSyncData1.updData.record.size() +
884 cloudSyncData1.delData.record.size(), static_cast<uint64_t>(insCount));
885 EXPECT_EQ(cloudSyncData1.delData.record.size(), 0u);
886
887 CloudSyncData cloudSyncData2;
888 EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData2), -E_UNFINISHED);
889 EXPECT_LT(cloudSyncData2.insData.record.size() + cloudSyncData2.updData.record.size() +
890 cloudSyncData2.delData.record.size(), static_cast<uint64_t>(insCount));
891
892 CloudSyncData cloudSyncData3;
893 EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData3), E_OK);
894 EXPECT_GT(cloudSyncData3.insData.record.size() + cloudSyncData3.updData.record.size() +
895 cloudSyncData3.delData.record.size(), static_cast<uint64_t>(insCount));
896 EXPECT_EQ(cloudSyncData3.insData.record.size(), 0u);
897
898 /**
899 * @tc.steps: Finished querying, the token has been release.
900 * @tc.expected: return -E_INVALID_ARGS.
901 */
902 EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData3), -E_INVALID_ARGS);
903 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
904 }
905
906 /**
907 * @tc.name: GetCloudData003
908 * @tc.desc: ReleaseContinueToken required when GetCloudDataNext interrupt
909 * @tc.type: FUNC
910 * @tc.require:
911 * @tc.author: bty
912 */
913 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData003, TestSize.Level1)
914 {
915 CreateLogTable();
916 int64_t insCount = 1024;
917 int64_t photoSize = 1024 * 8;
918 InitLogData(insCount, insCount, insCount, insCount);
919 CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
920
921 SetDbSchema(g_tableSchema);
922 ContinueToken token = nullptr;
923 CloudSyncData cloudSyncData;
924 EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
925 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
926 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
927 ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
928 token = nullptr;
929 EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData), -E_INVALID_ARGS);
930 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
931
932 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
933 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
934 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
935 ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
936 }
937
938 /**
939 * @tc.name: GetCloudData004
940 * @tc.desc: Test get cloudData when asset or assets is NULL
941 * @tc.type: FUNC
942 * @tc.require:
943 * @tc.author: bty
944 */
945 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData004, TestSize.Level1)
946 {
947 CreateLogTable();
948 int64_t insCount = 10;
949 int64_t photoSize = 10;
950 InitLogData(insCount, insCount, insCount, insCount);
951 CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
952
953 SetDbSchema(g_tableSchema);
954 sqlite3 *db = nullptr;
955 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
956 ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, "UPDATE " + g_tableName + " SET assert = NULL, asserts = NULL;"), E_OK);
957 sqlite3_close(db);
958 ContinueToken token = nullptr;
959 CloudSyncData cloudSyncData;
960 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
961 EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
962 EXPECT_NE(cloudSyncData.insData.record.size(), 0u);
963 for (const auto &item: cloudSyncData.insData.record) {
964 auto assert = item.find("assert");
965 auto asserts = item.find("asserts");
966 ASSERT_NE(assert, item.end());
967 ASSERT_NE(asserts, item.end());
968 EXPECT_EQ(assert->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
969 EXPECT_EQ(asserts->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
970 }
971 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
972 }
973
974 /**
975 * @tc.name: GetCloudData005
976 * @tc.desc: Commit the transaction before getCloudData finished
977 * @tc.type: FUNC
978 * @tc.require:
979 * @tc.author: bty
980 */
981 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData005, TestSize.Level1)
982 {
983 CreateLogTable();
984 int64_t insCount = 1024;
985 int64_t photoSize = 1024 * 8;
986 InitLogData(insCount, insCount, insCount, insCount);
987 CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
988
989 SetDbSchema(g_tableSchema);
990 ContinueToken token = nullptr;
991 CloudSyncData cloudSyncData;
992 EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
993 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
994 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
995 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
996
997 /**
998 * @tc.steps: GetCloudDataNext after the transaction ends, token will released internally
999 * @tc.expected: return -E_INVALID_DB.
1000 */
1001 ASSERT_EQ(g_cloudStore->GetCloudDataNext(token, cloudSyncData), -E_INVALID_DB);
1002 }
1003
1004 /**
1005 * @tc.name: GetCloudData006
1006 * @tc.desc: Test get cloud data which contains invalid status asset
1007 * @tc.type: FUNC
1008 * @tc.require:
1009 * @tc.author: bty
1010 */
1011 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData006, TestSize.Level1)
1012 {
1013 /**
1014 * @tc.steps:step1. Init data and set asset status to invalid num
1015 * @tc.expected: step1. return ok.
1016 */
1017 CreateLogTable();
1018 int64_t insCount = 1024;
1019 int64_t photoSize = 1024;
1020 InitLogData(insCount, insCount, insCount, insCount);
1021 CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
1022 Asset asset = g_localAsset;
1023 asset.status = static_cast<uint32_t>(AssetStatus::UPDATE) + 1;
1024 UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
1025 SetDbSchema(g_tableSchema);
1026
1027 /**
1028 * @tc.steps:step2. Get cloud data
1029 * @tc.expected: step2. return -E_CLOUD_INVALID_ASSET.
1030 */
1031 ContinueToken token = nullptr;
1032 CloudSyncData cloudSyncData;
1033 EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1034 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_CLOUD_INVALID_ASSET);
1035 EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1036 }
1037
1038 /**
1039 * @tc.name: GetInfoByPrimaryKeyOrGid001
1040 * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1041 * @tc.type: FUNC
1042 * @tc.require:
1043 * @tc.author: bty
1044 */
1045 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid001, TestSize.Level1)
1046 {
1047 int64_t insCount = 100;
1048 int64_t photoSize = 10;
1049 InitUserDataForAssetTest(insCount, photoSize);
1050 InitLogGid(insCount);
1051
1052 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1053 for (int i = 1; i <= insCount; i++) {
1054 VBucket vBucket;
1055 vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1056 VBucket assetInfo;
1057 DataInfoWithLog dataInfo;
1058 ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfo, assetInfo), E_OK);
1059 ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1060 auto entry1 = assetInfo.find("assert");
1061 auto entry2 = assetInfo.find("asserts");
1062 ASSERT_NE(entry1, assetInfo.end());
1063 ASSERT_NE(entry2, assetInfo.end());
1064 Asset asset = std::get<Asset>(entry1->second);
1065 EXPECT_EQ(asset.name, "Phone");
1066 Assets assets = std::get<Assets>(entry2->second);
1067 int id = 0;
1068 for (const auto &item: assets) {
1069 EXPECT_EQ(item.name, "Phone" + std::to_string(id++));
1070 }
1071 }
1072 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1073 }
1074
1075 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncData001, TestSize.Level1)
1076 {
1077 int64_t insCount = 10;
1078 int64_t photoSize = 10;
1079 InitUserDataForAssetTest(insCount, photoSize);
1080 InitLogGid(insCount);
1081
1082 DownloadData downloadData;
1083 ConstructMultiDownloadData(insCount, downloadData);
1084 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1085 EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1086 ContinueToken token = nullptr;
1087 CloudSyncData cloudSyncData;
1088 ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, 0L, token, cloudSyncData), E_OK);
1089 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1090 }
1091
1092 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset001, TestSize.Level1)
1093 {
1094 int64_t insCount = 10;
1095 int64_t photoSize = 10;
1096 InitUserDataForAssetTest(insCount, photoSize);
1097 InitLogGid(insCount);
1098 fillCloudAssetTest(insCount, AssetStatus::NORMAL, false);
1099 fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, false);
1100 fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, false);
1101 fillCloudAssetTest(insCount, AssetStatus::NORMAL, true);
1102 fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, true);
1103 fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, true);
1104 }
1105
1106 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, TestSize.Level1)
1107 {
1108 int64_t insCount = 10;
1109 int64_t photoSize = 10;
1110 InitUserDataForAssetTest(insCount, photoSize);
1111 InitLogGid(insCount);
1112
1113 sqlite3 *db = nullptr;
1114 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1115 sqlite3_stmt *stmt = nullptr;
1116 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName)
1117 + " WHERE data_key = 1;", stmt), E_OK);
1118 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1119 int64_t timeStamp = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1120 int errCode;
1121 SQLiteUtils::ResetStatement(stmt, true, errCode);
1122
1123 CloudSyncData syncData(g_tableName);
1124 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1125 ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1126 syncData.updData.rowid.push_back(1L);
1127 VBucket bucket1;
1128 Asset asset = g_localAsset;
1129 asset.size = "888";
1130 asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
1131 asset.status = static_cast<uint32_t>(AssetStatus::DELETE);
1132 bucket1.insert_or_assign("assert", asset);
1133 Assets assets;
1134 assets.push_back(asset);
1135 assets.push_back(asset);
1136 bucket1.insert_or_assign("asserts", assets);
1137 syncData.updData.assets.push_back(bucket1);
1138 syncData.updData.timestamp.push_back(timeStamp);
1139 ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1140 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1141
1142 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT assert, asserts FROM " + g_tableName + " WHERE rowid = 1;",
1143 stmt), E_OK);
1144 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1145 ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_NULL);
1146 ASSERT_EQ(sqlite3_column_type(stmt, 1), SQLITE_NULL);
1147 SQLiteUtils::ResetStatement(stmt, true, errCode);
1148 sqlite3_close(db);
1149 }
1150
1151 /**
1152 * @tc.name: FillCloudAsset003
1153 * @tc.desc: The twice fill have different assert columns
1154 * @tc.type: FUNC
1155 * @tc.require:
1156 * @tc.author: bty
1157 */
1158 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset003, TestSize.Level0)
1159 {
1160 int64_t insCount = 2;
1161 int64_t photoSize = 10;
1162 InitUserDataForAssetTest(insCount, photoSize);
1163 InitLogGid(insCount);
1164
1165 sqlite3 *db = nullptr;
1166 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1167 sqlite3_stmt *stmt = nullptr;
1168 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1169 " WHERE data_key in ('1', '2');", stmt), E_OK);
1170 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1171 int64_t timeStamp1 = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1172 int64_t timeStamp2 = static_cast<int64_t>(sqlite3_column_int64(stmt, 1));
1173 int errCode;
1174 SQLiteUtils::ResetStatement(stmt, true, errCode);
1175 sqlite3_close(db);
1176
1177 CloudSyncData syncData(g_tableName);
1178 syncData.updData.rowid.push_back(1L);
1179 syncData.updData.rowid.push_back(2L);
1180 VBucket bucket1, bucket2;
1181 Asset asset = g_localAsset;
1182 asset.size = "888";
1183 asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1184 Assets assets;
1185 assets.push_back(asset);
1186 assets.push_back(asset);
1187 bucket1.insert_or_assign("assert", asset);
1188 bucket2.insert_or_assign("assert", asset);
1189 bucket2.insert_or_assign("asserts", assets);
1190 syncData.updData.assets.push_back(bucket1);
1191 syncData.updData.assets.push_back(bucket2);
1192 syncData.updData.timestamp.push_back(timeStamp1);
1193 syncData.updData.timestamp.push_back(timeStamp2);
1194 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1195 ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1196 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1197 }
1198
1199 /**
1200 * @tc.name: FillCloudAsset004
1201 * @tc.desc: Test fill asset for insert type
1202 * @tc.type: FUNC
1203 * @tc.require:
1204 * @tc.author: bty
1205 */
1206 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset004, TestSize.Level0)
1207 {
1208 int64_t insCount = 2;
1209 int64_t photoSize = 10;
1210 InitUserDataForAssetTest(insCount, photoSize);
1211
1212 sqlite3 *db = nullptr;
1213 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1214 sqlite3_stmt *stmt = nullptr;
1215 ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1216 " WHERE data_key in ('1', '2');", stmt), E_OK);
1217 ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1218 std::vector<int64_t> timeVector;
1219 timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 0)));
1220 timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 1)));
1221 int errCode;
1222 SQLiteUtils::ResetStatement(stmt, true, errCode);
1223 sqlite3_close(db);
1224
1225 CloudSyncData syncData(g_tableName);
1226 for (int64_t i = 1; i <= insCount; ++i) {
1227 syncData.insData.rowid.push_back(i);
1228 VBucket bucket1;
1229 bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i));
1230 syncData.insData.extend.push_back(bucket1);
1231
1232 VBucket bucket2;
1233 Asset asset = g_localAsset;
1234 asset.size = "888";
1235 Assets assets;
1236 assets.push_back(asset);
1237 assets.push_back(asset);
1238 bucket2.insert_or_assign("assert", asset);
1239 bucket2.insert_or_assign("asserts", assets);
1240 syncData.insData.assets.push_back(bucket2);
1241 syncData.insData.timestamp.push_back(timeVector[i - 1]);
1242 }
1243 EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1244 ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::INSERT, syncData), E_OK);
1245 EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1246 }
1247
1248 /*
1249 * @tc.name: CalPrimaryKeyHash001
1250 * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is string
1251 * @tc.type: FUNC
1252 * @tc.require:
1253 * @tc.author: zhuwentao
1254 */
1255 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash001, TestSize.Level0)
1256 {
1257 /**
1258 * @tc.steps: step1. local insert one data, primary key is string
1259 * @tc.expected: OK.
1260 */
1261 std::string tableName = "user2";
1262 const std::string CREATE_LOCAL_TABLE_SQL =
1263 "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1264 "name TEXT PRIMARY KEY, age INT);";
1265 sqlite3 *db = nullptr;
1266 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1267 EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1268 ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1269 std::string name = "Local0";
1270 std::map<std::string, Type> primaryKey = {{"name", name}};
1271 string sql = "INSERT OR REPLACE INTO user2(name, age) VALUES ('Local" + std::to_string(0) + "', '18');";
1272 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1273 std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey);
1274 EXPECT_NE(result.size(), 0u);
1275 std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1276 /**
1277 * @tc.steps: step1. query timestamp use hashKey
1278 * @tc.expected: OK.
1279 */
1280 std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1281 sqlite3_stmt *statement = nullptr;
1282 int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1283 EXPECT_EQ(errCode, E_OK);
1284 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1285 if (errCode != E_OK) {
1286 SQLiteUtils::ResetStatement(statement, true, errCode);
1287 return;
1288 }
1289 errCode = SQLiteUtils::StepWithRetry(statement, false);
1290 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1291 Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1292 LOGD("get timestamp = %" PRIu64, timestamp);
1293 errCode = E_OK;
1294 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1295 errCode = -E_NOT_FOUND;
1296 }
1297 EXPECT_EQ(errCode, E_OK);
1298 SQLiteUtils::ResetStatement(statement, true, errCode);
1299 sqlite3_close(db);
1300 }
1301
1302 /*
1303 * @tc.name: CalPrimaryKeyHash002
1304 * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is int
1305 * @tc.type: FUNC
1306 * @tc.require:
1307 * @tc.author: zhuwentao
1308 */
1309 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash002, TestSize.Level0)
1310 {
1311 /**
1312 * @tc.steps: step1. local insert one data, primary key is int
1313 * @tc.expected: OK.
1314 */
1315 std::string tableName = "user3";
1316 const std::string CREATE_LOCAL_TABLE_SQL =
1317 "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1318 "id INT PRIMARY KEY, name TEXT);";
1319 sqlite3 *db = nullptr;
1320 ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1321 EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1322 ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1323 int64_t id = 1;
1324 std::map<std::string, Type> primaryKey = {{"id", id}};
1325 std::string sql = "INSERT OR REPLACE INTO " + tableName + " (id, name) VALUES ('" + '1' + "', 'Local" +
1326 std::to_string(0) + "');";
1327 EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1328 std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey);
1329 EXPECT_NE(result.size(), 0u);
1330 std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1331 /**
1332 * @tc.steps: step1. query timestamp use hashKey
1333 * @tc.expected: OK.
1334 */
1335 std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1336 sqlite3_stmt *statement = nullptr;
1337 int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1338 EXPECT_EQ(errCode, E_OK);
1339 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1340 if (errCode != E_OK) {
1341 SQLiteUtils::ResetStatement(statement, true, errCode);
1342 return;
1343 }
1344 errCode = SQLiteUtils::StepWithRetry(statement, false);
1345 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1346 Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1347 LOGD("get timestamp = %" PRIu64, timestamp);
1348 errCode = E_OK;
1349 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1350 errCode = -E_NOT_FOUND;
1351 }
1352 EXPECT_EQ(errCode, E_OK);
1353 SQLiteUtils::ResetStatement(statement, true, errCode);
1354 sqlite3_close(db);
1355 }
1356 }
1357 #endif // RELATIONAL_STORE