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 += (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 += (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 += (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: AR000D487C SR000D4878
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: AR000D487C SR000D4878
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: AR000D487C SR000D4878
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
281 /**
282 * @tc.steps: step4. Modify the database file.
283 */
284 std::string filePath;
285 #ifndef OMIT_MULTI_VER
286 filePath = GetKvStoreDirectory("corrupt4", DBConstant::DB_TYPE_LOCAL); // local database.
287 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
288 #endif // OMIT_MULTI_VER
289 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
290 filePath = GetKvStoreDirectory("corrupt5", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
291 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
292 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
293 KvStoreCorruptInfo corruptInfo;
294 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
295 std::placeholders::_2, std::placeholders::_3);
296 g_mgr.SetKvStoreCorruptionHandler(notifier);
297
298 /**
299 * @tc.steps: step5. Put data into the kvStore.
300 * @tc.expected: step5. The corrupt handler is called twice.
301 */
302 size_t infoSize = 0;
303 #ifndef OMIT_MULTI_VER
304 ASSERT_NE(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
305 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
306 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt4"), true);
307 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
308 g_kvDelegatePtr = nullptr;
309 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt4"), OK);
310 infoSize++;
311 #endif // OMIT_MULTI_VER
312 ASSERT_NE(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
313 infoSize++;
314 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
315 EXPECT_TRUE(corruptInfo.GetDatabaseInfoSize() >= infoSize); // 2 more callback
316 EXPECT_EQ(corruptInfo.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt5"), true);
317 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
318 g_kvNbDelegatePtr = nullptr;
319 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt5"), OK);
320 }
321
322 /**
323 * @tc.name: DatabaseCorruptionHandleTest004
324 * @tc.desc: Test the DeleteKvStore Interface and check whether the database files can be removed.
325 * @tc.type: FUNC
326 * @tc.require: AR000D487C SR000D4878
327 * @tc.author: wangbingquan
328 */
329 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest004, TestSize.Level1)
330 {
331 /**
332 * @tc.steps: step1. Get the kvStore.
333 * @tc.steps: step2. Put data into the store.
334 * @tc.steps: step3. Close the store.
335 */
336 CipherPassword passwd;
337 Key randomPassword;
338 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
339 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
340 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
341
342 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
343 g_mgr.GetKvStore("corrupt7", nbOption, g_kvNbDelegateCallback);
344 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
345 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
346
347 /**
348 * @tc.steps: step4. Modify the database file.
349 */
350 std::string filePath;
351 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
352 filePath = GetKvStoreDirectory("corrupt7", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
353 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
354 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
355 KvStoreCorruptInfo corruptInfo;
356 KvStoreCorruptInfo corruptInfoNew;
357 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
358 std::placeholders::_2, std::placeholders::_3);
359 g_mgr.SetKvStoreCorruptionHandler(notifier);
360 auto notifierNew = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfoNew, std::placeholders::_1,
361 std::placeholders::_2, std::placeholders::_3);
362 g_mgr.SetKvStoreCorruptionHandler(notifierNew);
363 /**
364 * @tc.steps: step5. Re-obtain the kvStore.
365 * @tc.expected: step5. Returns null kvstore.
366 */
367 size_t infoSize = 0;
368 ASSERT_NE(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
369 infoSize++;
370 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
371 EXPECT_EQ(corruptInfo.GetDatabaseInfoSize(), 0UL); // no callback
372 EXPECT_TRUE(corruptInfoNew.GetDatabaseInfoSize() >= infoSize); // 2 more callback
373 EXPECT_EQ(corruptInfoNew.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt7"), true);
374 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
375 g_kvNbDelegatePtr = nullptr;
376 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt7"), OK);
377 }
378
379 #ifndef OMIT_MULTI_VER
380 /**
381 * @tc.name: DatabaseCorruptionHandleTest005
382 * @tc.desc: Test the DeleteKvStore Interface and check whether the database files can be removed.
383 * @tc.type: FUNC
384 * @tc.require: AR000D487C SR000D4878
385 * @tc.author: wangbingquan
386 */
387 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseCorruptionHandleTest005, TestSize.Level1)
388 {
389 /**
390 * @tc.steps: step1. Get the kvStore.
391 * @tc.steps: step2. Put data into the store.
392 * @tc.steps: step3. Close the store.
393 */
394 CipherPassword passwd;
395 Key randomPassword;
396 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
397 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
398 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
399 KvStoreDelegate::Option option = {true, true, false, CipherType::DEFAULT, passwd};
400 g_mgr.GetKvStore("corrupt6", option, g_kvDelegateCallback);
401 ASSERT_TRUE(g_kvDelegatePtr != nullptr);
402 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
403 ASSERT_EQ(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
404
405 /**
406 * @tc.steps: step4. Modify the database file.
407 */
408 std::string filePath = GetKvStoreDirectory("corrupt6", DBConstant::DB_TYPE_LOCAL); // local database.
409 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
410 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
411 filePath = GetKvStoreDirectory("corrupt7", DBConstant::DB_TYPE_SINGLE_VER); // single ver database.
412 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath);
413 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath + "-wal");
414 KvStoreCorruptInfo corruptInfo;
415 KvStoreCorruptInfo corruptInfoNew;
416 auto notifier = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfo, std::placeholders::_1,
417 std::placeholders::_2, std::placeholders::_3);
418 g_mgr.SetKvStoreCorruptionHandler(notifier);
419 auto notifierNew = bind(&KvStoreCorruptInfo::CorruptCallBack, &corruptInfoNew, std::placeholders::_1,
420 std::placeholders::_2, std::placeholders::_3);
421 g_mgr.SetKvStoreCorruptionHandler(notifierNew);
422 /**
423 * @tc.steps: step5. Re-obtain the kvStore.
424 * @tc.expected: step5. Returns null kvstore.
425 */
426 size_t infoSize = 0;
427 ASSERT_NE(PutDataIntoDatabaseMultiVer(g_kvDelegatePtr), OK);
428 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
429 EXPECT_EQ(corruptInfoNew.IsDataBaseCorrupted(APP_NAME, USER_NAME, "corrupt6"), true);
430 EXPECT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK);
431 g_kvDelegatePtr = nullptr;
432 EXPECT_EQ(g_mgr.DeleteKvStore("corrupt6"), OK);
433 infoSize++;
434
435 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_CALLBACK_TIME));
436 EXPECT_EQ(corruptInfo.GetDatabaseInfoSize(), 0UL); // no callback
437 EXPECT_TRUE(corruptInfoNew.GetDatabaseInfoSize() >= infoSize); // 2 more callback
438 }
439 #endif // OMIT_MULTI_VER
440
441 namespace {
442 const uint32_t MODIFY_SIZE = 12; // Modify size is 12 * sizeof(uint32_t);
443 const uint32_t MODIFY_VALUE = 0xF3F3F3F3; // random value, make sure to destroy the page header.
TestDatabaseIntegrityCheckOption(const std::string & storeId,bool isEncrypted)444 void TestDatabaseIntegrityCheckOption(const std::string &storeId, bool isEncrypted)
445 {
446 KvStoreNbDelegate::Option nbOption = {true, false, isEncrypted};
447 nbOption.isNeedIntegrityCheck = false;
448 nbOption.isNeedRmCorruptedDb = false;
449 if (isEncrypted) {
450 Key randPassword;
451 DistributedDBToolsUnitTest::GetRandomKeyValue(randPassword, PASSWD_SIZE);
452 ASSERT_EQ(nbOption.passwd.SetValue(randPassword.data(), randPassword.size()), CipherPassword::ErrorCode::OK);
453 }
454 auto filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
455 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
456 ASSERT_EQ(g_kvNbDelegateStatus, OK);
457 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
458 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
459 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
460
461 /**
462 * @tc.steps: step1. Modify the database file header to destroy the header and call the GetKvStore.
463 * @tc.expected: step1. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
464 */
465 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, 0, MODIFY_SIZE, MODIFY_VALUE);
466 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
467 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
468 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
469
470 /**
471 * @tc.steps: step2. call the GetKvStore with integrity check option is true.
472 * @tc.expected: step2. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
473 */
474 nbOption.isNeedIntegrityCheck = true;
475 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
476 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
477 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
478
479 /**
480 * @tc.steps: step3. call the GetKvStore with remove corrupted database option is true.
481 * @tc.expected: step3. Returns non-null kv store and the errCode is OK.
482 */
483 nbOption.isNeedIntegrityCheck = false;
484 nbOption.isNeedRmCorruptedDb = true;
485 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
486 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
487
488 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
489 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
490
491 /**
492 * @tc.steps: step4. Modify the second page of the database file and Get the kv store.
493 * @tc.expected: step4. Returns non-null kv store and the errCode is OK(GetKvStore skip the check of the page 2).
494 */
495 size_t filePos = isEncrypted ? 1024 : 4096; // 1024 and 4096 is the page size.
496 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, filePos, MODIFY_SIZE, MODIFY_VALUE);
497 nbOption.isNeedRmCorruptedDb = false;
498 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
499 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
500 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
501
502 /**
503 * @tc.steps: step5. Get the kv store with check the integrity.
504 * @tc.expected: step5. Returns null kv store and the errCode is INVALID_PASSWD_OR_CORRUPTED_DB.
505 */
506 nbOption.isNeedIntegrityCheck = true;
507 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
508 ASSERT_EQ(g_kvNbDelegateStatus, INVALID_PASSWD_OR_CORRUPTED_DB);
509 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
510
511 /**
512 * @tc.steps: step5. Get the kv store with check the integrity and the rm corrupted database option.
513 * @tc.expected: step5. Returns non-null kv store and the errCode is OK.
514 */
515 nbOption.isNeedRmCorruptedDb = true;
516 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
517 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
518 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
519 EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK);
520 }
521 }
522
523 /**
524 * @tc.name: DatabaseRebuildTest001
525 * @tc.desc: Test DB rebuild.
526 * @tc.type: FUNC
527 * @tc.require:
528 * @tc.author: liaoyonghuang
529 */
530 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseRebuildTest001, TestSize.Level0)
531 {
532 /**
533 * @tc.steps: step1. Get the kv store
534 * @tc.expected: step1. Returns OK.
535 */
536 KvStoreNbDelegate::Option nbOption;
537 nbOption.isNeedIntegrityCheck = false;
538 nbOption.isNeedRmCorruptedDb = true;
539 std::string storeId = "DatabaseRebuildTest001";
540 auto filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
541 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
542 ASSERT_EQ(g_kvNbDelegateStatus, OK);
543 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
544 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
545 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
546 /**
547 * @tc.steps: step2. Modify database file and get the kv store
548 * @tc.expected: step2. Check database status OK.
549 */
550 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, 0, MODIFY_SIZE, MODIFY_VALUE);
551 g_mgr.GetKvStore(storeId, nbOption, g_kvNbDelegateCallback);
552 ASSERT_EQ(g_kvNbDelegateStatus, OK);
553 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
554 KvStoreNbDelegate::DatabaseStatus actualStatus = g_kvNbDelegatePtr->GetDatabaseStatus();
555 EXPECT_EQ(actualStatus.isRebuild, true);
556 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
557 EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK);
558 }
559
560 /**
561 * @tc.name: DatabaseIntegrityCheck001
562 * @tc.desc: Test the integrity check option.
563 * @tc.type: FUNC
564 * @tc.require: AR000D487C SR000D4878
565 * @tc.author: wangbingquan
566 */
567 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseIntegrityCheck001, TestSize.Level2)
568 {
569 LOGI("Begin to check the unencrypted database");
570 TestDatabaseIntegrityCheckOption("integrity_check001", false);
571 std::this_thread::sleep_for(std::chrono::milliseconds(500));
572 LOGI("Begin to check the encrypted database");
573 TestDatabaseIntegrityCheckOption("integrity_check002", true);
574 }
575
576 /**
577 * @tc.name: DatabaseIntegrityCheck002
578 * @tc.desc: Test the integrity check interface.
579 * @tc.type: FUNC
580 * @tc.require: AR000D487C SR000D4878
581 * @tc.author: wangbingquan
582 */
583 HWTEST_F(DistributedDBInterfacesDatabaseCorruptTest, DatabaseIntegrityCheck002, TestSize.Level1)
584 {
585 CipherPassword passwd;
586 KvStoreNbDelegate::Option nbOption = {true, false, false, CipherType::DEFAULT, passwd};
587 nbOption.isNeedIntegrityCheck = true;
588 nbOption.isNeedRmCorruptedDb = true;
589 auto filePath = GetKvStoreDirectory("integrity021", DBConstant::DB_TYPE_SINGLE_VER);
590 for (uint32_t i = 1; i < 4; i++) {
591 LOGI("%u th test!", i);
592 g_mgr.GetKvStore("integrity021", nbOption, g_kvNbDelegateCallback);
593 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
594 ASSERT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
595 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
596 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
597 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, i * 4096, MODIFY_SIZE, MODIFY_VALUE); // page size 4096
598 g_mgr.GetKvStore("integrity021", nbOption, g_kvNbDelegateCallback);
599 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
600 EXPECT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
601 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
602 EXPECT_EQ(g_mgr.DeleteKvStore("integrity021"), OK);
603 }
604 LOGI("Begin the encrypted check");
605 Key randomPassword;
606 DistributedDBToolsUnitTest::GetRandomKeyValue(randomPassword, PASSWD_SIZE);
607 int errCode = passwd.SetValue(randomPassword.data(), randomPassword.size());
608 ASSERT_EQ(errCode, CipherPassword::ErrorCode::OK);
609 nbOption = {true, false, true, CipherType::DEFAULT, passwd};
610 nbOption.isNeedIntegrityCheck = true;
611 nbOption.isNeedRmCorruptedDb = true;
612 filePath = GetKvStoreDirectory("integrity022", DBConstant::DB_TYPE_SINGLE_VER);
613 for (uint32_t i = 1; i < 4; i++) {
614 LOGI("%u th test the encrypted database!", i);
615 g_mgr.GetKvStore("integrity022", nbOption, g_kvNbDelegateCallback);
616 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
617 ASSERT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
618 ASSERT_EQ(PutDataIntoDatabaseSingleVer(g_kvNbDelegatePtr), OK);
619 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
620 DistributedDBToolsUnitTest::ModifyDatabaseFile(filePath, i * 1024, MODIFY_SIZE, MODIFY_VALUE); // page size 1024
621 g_mgr.GetKvStore("integrity022", nbOption, g_kvNbDelegateCallback);
622 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
623 EXPECT_EQ(g_kvNbDelegatePtr->CheckIntegrity(), OK);
624 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
625 EXPECT_EQ(g_mgr.DeleteKvStore("integrity022"), OK);
626 }
627 }