1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <chrono>
17 #include <functional>
18 #include <gtest/gtest.h>
19 #include <thread>
20
21 #include "db_common.h"
22 #include "db_constant.h"
23 #include "distributeddb_tools_unit_test.h"
24
25 using namespace testing::ext;
26 using namespace DistributedDB;
27 using namespace DistributedDBUnitTest;
28
29 namespace {
30 const std::string APP_NAME = "app";
31 const std::string USER_NAME = "account0";
32 const int PASSWD_SIZE = 20;
33 const int WAIT_CALLBACK_TIME = 100;
34 KvStoreDelegateManager g_mgr(APP_NAME, USER_NAME);
35 string g_testDir;
36 KvStoreConfig g_config;
37
38 #ifndef OMIT_MULTI_VER
39 DBStatus g_kvDelegateStatus = INVALID_ARGS;
40 KvStoreDelegate *g_kvDelegatePtr = nullptr;
41 auto g_kvDelegateCallback = std::bind(&DistributedDBToolsUnitTest::KvStoreDelegateCallback, std::placeholders::_1,
42 std::placeholders::_2, std::ref(g_kvDelegateStatus), std::ref(g_kvDelegatePtr));
43 #endif // OMIT_MULTI_VER
44
45 DBStatus g_kvNbDelegateStatus = INVALID_ARGS;
46 KvStoreNbDelegate *g_kvNbDelegatePtr = nullptr;
47 auto g_kvNbDelegateCallback = std::bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback,
48 std::placeholders::_1, std::placeholders::_2, std::ref(g_kvNbDelegateStatus), std::ref(g_kvNbDelegatePtr));
49
GetKvStoreDirectory(const std::string & storeId,int databaseType)50 std::string GetKvStoreDirectory(const std::string &storeId, int databaseType)
51 {
52 std::string identifier = USER_NAME + "-" + APP_NAME + "-" + storeId;
53 std::string hashIdentifierName = DBCommon::TransferHashString(identifier);
54 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifierName);
55 std::string filePath = g_testDir + "/" + identifierName + "/";
56 if (databaseType == DBConstant::DB_TYPE_LOCAL) { // local
57 filePath += (std::string(DBConstant::LOCAL_SUB_DIR) + "/" + DBConstant::LOCAL_DATABASE_NAME +
58 DBConstant::DB_EXTENSION);
59 } else if (databaseType == DBConstant::DB_TYPE_SINGLE_VER) { // single ver
60 filePath += (std::string(DBConstant::SINGLE_SUB_DIR) + "/" + DBConstant::MAINDB_DIR + "/" +
61 DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION);
62 } else if (databaseType == DBConstant::DB_TYPE_MULTI_VER) { // multi ver
63 filePath += (std::string(DBConstant::MULTI_SUB_DIR) + "/" + DBConstant::MULTI_VER_DATA_STORE +
64 DBConstant::DB_EXTENSION);
65 } else {
66 filePath = "";
67 }
68
69 return filePath;
70 }
71
PutDataIntoDatabaseSingleVer(KvStoreNbDelegate * kvNbDelegate)72 int PutDataIntoDatabaseSingleVer(KvStoreNbDelegate *kvNbDelegate)
73 {
74 if (kvNbDelegate == nullptr) {
75 return DBStatus::DB_ERROR;
76 }
77 Key key;
78 Value value;
79 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
80 DistributedDBToolsUnitTest::GetRandomKeyValue(value);
81 return kvNbDelegate->Put(key, value);
82 }
83 #ifndef OMIT_MULTI_VER
PutDataIntoDatabaseMultiVer(KvStoreDelegate * kvDelegate)84 int PutDataIntoDatabaseMultiVer(KvStoreDelegate *kvDelegate)
85 {
86 if (kvDelegate == nullptr) {
87 return DBStatus::DB_ERROR;
88 }
89 Key key;
90 Value value;
91 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
92 DistributedDBToolsUnitTest::GetRandomKeyValue(value);
93 return kvDelegate->Put(key, value);
94 }
95 #endif // OMIT_MULTI_VER
96 }
97
98 class DistributedDBInterfacesDatabaseCorruptTest : public testing::Test {
99 public:
100 static void SetUpTestCase(void);
101 static void TearDownTestCase(void);
102 void SetUp();
103 void TearDown();
104 };
105
SetUpTestCase(void)106 void DistributedDBInterfacesDatabaseCorruptTest::SetUpTestCase(void)
107 {
108 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
109 g_config.dataDir = g_testDir;
110 g_mgr.SetKvStoreConfig(g_config);
111 }
112
TearDownTestCase(void)113 void DistributedDBInterfacesDatabaseCorruptTest::TearDownTestCase(void)
114 {
115 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
116 LOGE("rm test db files error!");
117 }
118 }
119
SetUp(void)120 void DistributedDBInterfacesDatabaseCorruptTest::SetUp(void)
121 {
122 #ifndef OMIT_MULTI_VER
123 DistributedDBToolsUnitTest::PrintTestCaseInfo();
124 g_kvDelegateStatus = INVALID_ARGS;
125 g_kvDelegatePtr = nullptr;
126 #endif // OMIT_MULTI_VER
127 }
128
TearDown(void)129 void DistributedDBInterfacesDatabaseCorruptTest::TearDown(void)
130 {
131 g_mgr.SetKvStoreCorruptionHandler(nullptr);
132 }
133
134 #ifndef OMIT_MULTI_VER
135 /**
136 * @tc.name: DatabaseCorruptionHandleTest001
137 * @tc.desc: Check the corruption detect without setting the corrupt handler.
138 * @tc.type: FUNC
139 * @tc.require:
140 * @tc.author: wangbingquan
141 */
142 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest001, TestSize.Level3)
143 {
144 /**
145 * @tc.steps: step1. Obtain the kvStore.
146 * @tc.steps: step2. Put one data into the store.
147 * @tc.steps: step3. Close the store.
148 */
149 CipherPassword passwd;
150 Key randomPassword;
151 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
152 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
153 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
154 KvStoreDelegate::Option option = {true, true, false, CipherType::DEFAULT, passwd};
155 g_mgr.GetKvStore("corrupt1", option, g_kvDelegateCallback);
156 ASSERT_TRUE(g_kvDelegatePtr != nullptr);
157 EXPECT_TRUE(g_kvDelegateStatus == OK);
158 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
159 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
160 g_kvDelegatePtr = nullptr;
161
162 /**
163 * @tc.steps: step4. Modify the database file.
164 */
165 std::string filePath = GetKvStoreDirectory("corrupt1", DBConstant::DB_TYPE_LOCAL); // local database.
166 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
167
168 /**
169 * @tc.steps: step5. Re-obtain the kvStore.
170 * @tc.expected: step5. Returns null kvstore.
171 */
172 g_mgr.GetKvStore("corrupt1", option, g_kvDelegateCallback);
173 ASSERT_TRUE(g_kvDelegatePtr == nullptr);
174 EXPECT_TRUE(g_kvDelegateStatus == INVALID_PASSWD_OR_CORRUPTED_DB);
175 g_mgr.DeleteKvStore("corrupt1");
176 }
177 #endif // OMIT_MULTI_VER
178
179 /**
180 * @tc.name: DatabaseCorruptionHandleTest002
181 * @tc.desc: Get kv store through different parameters for the same storeID.
182 * @tc.type: FUNC
183 * @tc.require:
184 * @tc.author: wangbingquan
185 */
186 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest002, TestSize.Level1)
187 {
188 /**
189 * @tc.steps: step1. Get the kvStore.
190 * @tc.steps: step2. Put data into the store.
191 * @tc.steps: step3. Close the store.
192 */
193 CipherPassword passwd;
194 Key randomPassword;
195 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
196 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
197 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
198 #ifndef OMIT_MULTI_VER
199 KvStoreDelegate::Option option = {true, false, false, CipherType::DEFAULT, passwd};
200 g_mgr.GetKvStore("corrupt2", option, g_kvDelegateCallback);
201 ASSERT_TRUE(g_kvDelegatePtr != nullptr);
202 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
203 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
204 g_kvDelegatePtr = nullptr;
205 #endif // OMIT_MULTI_VER
206
207 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
208 g_mgr.GetKvStore("corrupt3", nbOption, g_kvNbDelegateCallback);
209 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
210 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
211 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
212 g_kvNbDelegatePtr = nullptr;
213
214 /**
215 * @tc.steps: step4. Modify the database file.
216 */
217 std::string filePath;
218 #ifndef OMIT_MULTI_VER
219 filePath = GetKvStoreDirectory("corrupt2", DBConstant::DB_TYPE_MULTI_VER);
220 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
221 #endif // OMIT_MULTI_VER
222 filePath = GetKvStoreDirectory("corrupt3", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
223 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
224 KvStoreCorruptInfo corruptInfo;
225 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
226 std::placeholders::_2, std::placeholders::_3);
227 g_mgr.SetKvStoreCorruptionHandler(notifier);
228 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
229 /**
230 * @tc.steps: step5. Re-obtain the kvStore.
231 * @tc.expected: step5. Returns null kvstore.
232 */
233 size_t infoSize = 0;
234 #ifndef OMIT_MULTI_VER
235 g_mgr.GetKvStore("corrupt2", option, g_kvDelegateCallback);
236 ASSERT_TRUE(g_kvDelegateStatus != OK);
237 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt2"), true);
238 g_mgr.DeleteKvStore("corrupt2");
239 infoSize++;
240 #endif // OMIT_MULTI_VER
241
242 g_mgr.GetKvStore("corrupt3", nbOption, g_kvNbDelegateCallback);
243 ASSERT_TRUE(g_kvNbDelegateStatus != OK);
244 infoSize++;
245 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
246 EXPECT_EQ(corruptInfo.GetDatabaseInfoSize(), infoSize); // 2 callback
247 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt3"), true);
248 g_mgr.DeleteKvStore("corrupt3");
249 }
250
251 /**
252 * @tc.name: DatabaseCorruptionHandleTest003
253 * @tc.desc: Test the CloseKvStore Interface and check whether the database file can be closed.
254 * @tc.type: FUNC
255 * @tc.require:
256 * @tc.author: wangbingquan
257 */
258 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest003, TestSize.Level1)
259 {
260 /**
261 * @tc.steps: step1. Get the kvStore.
262 * @tc.steps: step2. Put data into the store.
263 * @tc.steps: step3. Close the store.
264 */
265 CipherPassword passwd;
266 Key randomPassword;
267 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
268 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
269 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
270 #ifndef OMIT_MULTI_VER
271 KvStoreDelegate::Option option = {true, true, false, CipherType::DEFAULT, passwd};
272 g_mgr.GetKvStore("corrupt4", option, g_kvDelegateCallback);
273 ASSERT_TRUE(g_kvDelegatePtr != nullptr);
274 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
275 #endif // OMIT_MULTI_VER
276 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
277 g_mgr.GetKvStore("corrupt5", nbOption, g_kvNbDelegateCallback);
278 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
279 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
280 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
281 g_kvNbDelegatePtr = nullptr;
282
283 /**
284 * @tc.steps: step4. Modify the database file.
285 */
286 std::string filePath;
287 #ifndef OMIT_MULTI_VER
288 filePath = GetKvStoreDirectory("corrupt4", DBConstant::DB_TYPE_LOCAL); // local database.
289 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
290 #endif // OMIT_MULTI_VER
291 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
292 filePath = GetKvStoreDirectory("corrupt5", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
293 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
294 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
295 KvStoreCorruptInfo corruptInfo;
296 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
297 std::placeholders::_2, std::placeholders::_3);
298 g_mgr.SetKvStoreCorruptionHandler(notifier);
299
300 /**
301 * @tc.steps: step5. Put data into the kvStore.
302 * @tc.expected: step5. The corrupt handler is called twice.
303 */
304 size_t infoSize = 0;
305 #ifndef OMIT_MULTI_VER
306 ASSERT_NE(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
307 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
308 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt4"), true);
309 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
310 g_kvDelegatePtr = nullptr;
311 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt4"), OK);
312 infoSize++;
313 #endif // OMIT_MULTI_VER
314 g_mgr.GetKvStore("corrupt5", nbOption, g_kvNbDelegateCallback);
315 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
316 ASSERT_NE(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
317 infoSize++;
318 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
319 EXPECT_TRUE(corruptInfo.GetDatabaseInfoSize() >= infoSize); // 2 more callback
320 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt5"), true);
321 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt5"), OK);
322 }
323
324 /**
325 * @tc.name: DatabaseCorruptionHandleTest004
326 * @tc.desc: Test the DeleteKvStore Interface and check whether the database files can be removed.
327 * @tc.type: FUNC
328 * @tc.require:
329 * @tc.author: wangbingquan
330 */
331 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest004, TestSize.Level1)
332 {
333 /**
334 * @tc.steps: step1. Get the kvStore.
335 * @tc.steps: step2. Put data into the store.
336 * @tc.steps: step3. Close the store.
337 */
338 CipherPassword passwd;
339 Key randomPassword;
340 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
341 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
342 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
343
344 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
345 g_mgr.GetKvStore("corrupt7", nbOption, g_kvNbDelegateCallback);
346 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
347 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
348 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
349 g_kvNbDelegatePtr = nullptr;
350
351 /**
352 * @tc.steps: step4. Modify the database file.
353 */
354 std::string filePath;
355 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
356 filePath = GetKvStoreDirectory("corrupt7", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
357 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
358 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
359 KvStoreCorruptInfo corruptInfo;
360 KvStoreCorruptInfo corruptInfoNew;
361 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
362 std::placeholders::_2, std::placeholders::_3);
363 g_mgr.SetKvStoreCorruptionHandler(notifier);
364 auto notifierNew = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfoNew, std::placeholders::_1,
365 std::placeholders::_2, std::placeholders::_3);
366 g_mgr.SetKvStoreCorruptionHandler(notifierNew);
367 /**
368 * @tc.steps: step5. Re-obtain the kvStore.
369 * @tc.expected: step5. Returns null kvstore.
370 */
371 g_mgr.GetKvStore("corrupt7", nbOption, g_kvNbDelegateCallback);
372 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
373 size_t infoSize = 0;
374 ASSERT_NE(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
375 infoSize++;
376 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
377 EXPECT_EQ(corruptInfo.GetDatabaseInfoSize(), 0UL); // no callback
378 EXPECT_TRUE(corruptInfoNew.GetDatabaseInfoSize() >= infoSize); // 2 more callback
379 EXPECT_EQ(corruptInfoNew.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt7"), true);
380 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt7"), OK);
381 }
382
383 #ifndef OMIT_MULTI_VER
384 /**
385 * @tc.name: DatabaseCorruptionHandleTest005
386 * @tc.desc: Test the DeleteKvStore Interface and check whether the database files can be removed.
387 * @tc.type: FUNC
388 * @tc.require:
389 * @tc.author: wangbingquan
390 */
391 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest005, TestSize.Level1)
392 {
393 /**
394 * @tc.steps: step1. Get the kvStore.
395 * @tc.steps: step2. Put data into the store.
396 * @tc.steps: step3. Close the store.
397 */
398 CipherPassword passwd;
399 Key randomPassword;
400 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
401 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
402 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
403 KvStoreDelegate::Option option = {true, true, false, CipherType::DEFAULT, passwd};
404 g_mgr.GetKvStore("corrupt6", option, g_kvDelegateCallback);
405 ASSERT_TRUE(g_kvDelegatePtr != nullptr);
406 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
407 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
408
409 /**
410 * @tc.steps: step4. Modify the database file.
411 */
412 std::string filePath = GetKvStoreDirectory("corrupt6", DBConstant::DB_TYPE_LOCAL); // local database.
413 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
414 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
415 filePath = GetKvStoreDirectory("corrupt7", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
416 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
417 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
418 KvStoreCorruptInfo corruptInfo;
419 KvStoreCorruptInfo corruptInfoNew;
420 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
421 std::placeholders::_2, std::placeholders::_3);
422 g_mgr.SetKvStoreCorruptionHandler(notifier);
423 auto notifierNew = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfoNew, std::placeholders::_1,
424 std::placeholders::_2, std::placeholders::_3);
425 g_mgr.SetKvStoreCorruptionHandler(notifierNew);
426 /**
427 * @tc.steps: step5. Re-obtain the kvStore.
428 * @tc.expected: step5. Returns null kvstore.
429 */
430 size_t infoSize = 0;
431 ASSERT_NE(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
432 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
433 EXPECT_EQ(corruptInfoNew.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt6"), true);
434 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
435 g_kvDelegatePtr = nullptr;
436 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt6"), OK);
437 infoSize++;
438
439 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
440 EXPECT_EQ(corruptInfo.GetDatabaseInfoSize(), 0UL); // no callback
441 EXPECT_TRUE(corruptInfoNew.GetDatabaseInfoSize() >= infoSize); // 2 more callback
442 }
443 #endif // OMIT_MULTI_VER
444
445 namespace {
446 const uint32_t MODIFY_SIZE = 12; // Modify size is 12 * sizeof(uint32_t);
447 const uint32_t MODIFY_VALUE = 0xF3F3F3F3; // random value, make sure to destroy the page header.
TestDatabaseIntegrityCheckOption(const std::string & storeId,bool isEncrypted)448 void TestDatabaseIntegrityCheckOption(const std::string &storeId, bool isEncrypted)
449 {
450 KvStoreNbDelegate::Option nbOption = {true, false, isEncrypted};
451 nbOption.isNeedIntegrityCheck = false;
452 nbOption.isNeedRmCorruptedDb = false;
453 if (isEncrypted) {
454 Key randPassword;
455 DistributedDBToolsUnitTest::GetRandomKeyValue(randPassword, PASSWD_SIZE);
456 ASSERT_EQ(nbOption.passwd.SetValue(randPassword.data(), randPassword.size()), CipherPassword::ErrorCode::OK);
457 }
458 auto filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
459 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
460 ASSERT_EQ(g_kvNbDelegateStatus, OK);
461 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
462 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
463 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
464
465 /**
466 * @tc.steps: step1. Modify the database file header to destroy the header and call the GetKvStore.
467 * @tc.expected: step1. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
468 */
469 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, 0, MODIFY_SIZE, MODIFY_VALUE);
470 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
471 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
472 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
473
474 /**
475 * @tc.steps: step2. call the GetKvStore with integrity check option is true.
476 * @tc.expected: step2. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
477 */
478 nbOption.isNeedIntegrityCheck = true;
479 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
480 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
481 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
482
483 /**
484 * @tc.steps: step3. call the GetKvStore with remove corrupted database option is true.
485 * @tc.expected: step3. Returns non-null kv store and the errCode is OK.
486 */
487 nbOption.isNeedIntegrityCheck = false;
488 nbOption.isNeedRmCorruptedDb = true;
489 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
490 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
491
492 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
493 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
494
495 /**
496 * @tc.steps: step4. Modify the second page of the database file and Get the kv store.
497 * @tc.expected: step4. Returns non-null kv store and the errCode is OK(GetKvStore skip the check of the page 2).
498 */
499 size_t filePos = isEncrypted ? 1024 : 4096; // 1024 and 4096 is the page size.
500 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, filePos, MODIFY_SIZE, MODIFY_VALUE);
501 nbOption.isNeedRmCorruptedDb = false;
502 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
503 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
504 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
505
506 /**
507 * @tc.steps: step5. Get the kv store with check the integrity.
508 * @tc.expected: step5. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
509 */
510 nbOption.isNeedIntegrityCheck = true;
511 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
512 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
513 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
514
515 /**
516 * @tc.steps: step5. Get the kv store with check the integrity and the rm corrupted database option.
517 * @tc.expected: step5. Returns non-null kv store and the errCode is OK.
518 */
519 nbOption.isNeedRmCorruptedDb = true;
520 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
521 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
522 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
523 EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK);
524 }
525 }
526
527 /**
528 * @tc.name: DatabaseRebuildTest001
529 * @tc.desc: Test DB rebuild.
530 * @tc.type: FUNC
531 * @tc.require:
532 * @tc.author: liaoyonghuang
533 */
534 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseRebuildTest001, TestSize.Level0)
535 {
536 /**
537 * @tc.steps: step1. Get the kv store
538 * @tc.expected: step1. Returns OK.
539 */
540 KvStoreNbDelegate::Option nbOption;
541 nbOption.isNeedIntegrityCheck = false;
542 nbOption.isNeedRmCorruptedDb = true;
543 std::string storeId = "DatabaseRebuildTest001";
544 auto filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
545 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
546 ASSERT_EQ(g_kvNbDelegateStatus, OK);
547 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
548 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
549 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
550 /**
551 * @tc.steps: step2. Modify database file and get the kv store
552 * @tc.expected: step2. Check database status OK.
553 */
554 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, 0, MODIFY_SIZE, MODIFY_VALUE);
555 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
556 ASSERT_EQ(g_kvNbDelegateStatus, OK);
557 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
558 KvStoreNbDelegate::DatabaseStatus actualStatus = g_kvNbDelegatePtr->GetDatabaseStatus();
559 EXPECT_EQ(actualStatus.isRebuild, true);
560 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
561 EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK);
562 }
563
564 /**
565 * @tc.name: DatabaseIntegrityCheck001
566 * @tc.desc: Test the integrity check option.
567 * @tc.type: FUNC
568 * @tc.require:
569 * @tc.author: wangbingquan
570 */
571 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseIntegrityCheck001, TestSize.Level2)
572 {
573 LOGI("Begin to check the unencrypted database");
574 TestDatabaseIntegrityCheckOption("integrity_check001", false);
575 std::this_thread::sleep_for(std::chrono::milliseconds(500));
576 LOGI("Begin to check the encrypted database");
577 TestDatabaseIntegrityCheckOption("integrity_check002", true);
578 }
579
580 /**
581 * @tc.name: DatabaseIntegrityCheck002
582 * @tc.desc: Test the integrity check interface.
583 * @tc.type: FUNC
584 * @tc.require:
585 * @tc.author: wangbingquan
586 */
587 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseIntegrityCheck002, TestSize.Level1)
588 {
589 CipherPassword passwd;
590 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
591 nbOption.isNeedIntegrityCheck = true;
592 nbOption.isNeedRmCorruptedDb = true;
593 auto filePath = GetKvStoreDirectory("integrity021", DBConstant::DB_TYPE_SINGLE_VER);
594 for (uint32_t i = 1; i < 4; i++) {
595 LOGI("%u th test!", i);
596 g_mgr.GetKvStore("integrity021", nbOption, g_kvNbDelegateCallback);
597 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
598 ASSERT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
599 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
600 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
601 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, i * 4096, MODIFY_SIZE, MODIFY_VALUE); // page size 4096
602 g_mgr.GetKvStore("integrity021", nbOption, g_kvNbDelegateCallback);
603 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
604 EXPECT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
605 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
606 EXPECT_EQ(g_mgr.DeleteKvStore("integrity021"), OK);
607 }
608 LOGI("Begin the encrypted check");
609 Key randomPassword;
610 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
611 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
612 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
613 nbOption = {true, false, true, CipherType::DEFAULT, passwd};
614 nbOption.isNeedIntegrityCheck = true;
615 nbOption.isNeedRmCorruptedDb = true;
616 filePath = GetKvStoreDirectory("integrity022", DBConstant::DB_TYPE_SINGLE_VER);
617 for (uint32_t i = 1; i < 4; i++) {
618 LOGI("%u th test the encrypted database!", i);
619 g_mgr.GetKvStore("integrity022", nbOption, g_kvNbDelegateCallback);
620 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
621 ASSERT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
622 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
623 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
624 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, i * 1024, MODIFY_SIZE, MODIFY_VALUE); // page size 1024
625 g_mgr.GetKvStore("integrity022", nbOption, g_kvNbDelegateCallback);
626 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
627 EXPECT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
628 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
629 EXPECT_EQ(g_mgr.DeleteKvStore("integrity022"), OK);
630 }
631 }