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 }