1 /*
2 * Copyright (c) 2022 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 #include "store_factory.h"
16
17 #include <cerrno>
18 #include <cstdio>
19 #include <gtest/gtest.h>
20 #include <sys/types.h>
21 #include <vector>
22
23 #include "backup_manager.h"
24 #include "file_ex.h"
25 #include "hks_api.h"
26 #include "hks_param.h"
27 #include "security_manager.h"
28 #include "store_manager.h"
29 #include "store_util.h"
30 #include "sys/stat.h"
31 #include "types.h"
32 namespace {
33 using namespace testing::ext;
34 using namespace OHOS::DistributedKv;
35
36 static StoreId storeId = { "single_test" };
37 static AppId appId = { "rekey" };
38 static Options options = {
39 .encrypt = true,
40 .securityLevel = S1,
41 .area = EL1,
42 .kvStoreType = SINGLE_VERSION,
43 .baseDir = "/data/service/el1/public/database/rekey",
44 };
45 static constexpr const char *ROOT_KEY_ALIAS = "distributeddb_client_root_key";
46 static constexpr const char *HKS_BLOB_TYPE_AAD = "distributeddata_client";
47
48 class StoreFactoryTest : public testing::Test {
49 public:
50 using DBStore = DistributedDB::KvStoreNbDelegate;
51 using DBManager = DistributedDB::KvStoreDelegateManager;
52 using DBOption = DistributedDB::KvStoreNbDelegate::Option;
53 using DBPassword = SecurityManager::DBPassword;
54 using DBStatus = DistributedDB::DBStatus;
55
56 static constexpr int OUTDATED_TIME = (24 * 500);
57 static constexpr int NOT_OUTDATED_TIME = (24 * 50);
58
59 static void SetUpTestCase(void);
60 static void TearDownTestCase(void);
61 void SetUp();
62 void TearDown();
63
64 std::chrono::system_clock::time_point GetDate(const std::string &name, const std::string &path);
65 bool ChangeKeyDate(const std::string &name, const std::string &path, int duration, const std::vector<uint8_t> &key);
66 bool MoveToRekeyPath(Options options, StoreId storeId);
67 std::shared_ptr<StoreFactoryTest::DBManager> GetDBManager(const std::string &path, const AppId &appId);
68 DBOption GetOption(const Options &options, const DBPassword &dbPassword);
69 DBStatus ChangeKVStoreDate(const std::string &storeId, std::shared_ptr<DBManager> dbManager, const Options &options,
70 DBPassword &dbPassword, int time);
71 bool ModifyDate(int time);
72 bool Encrypt(const std::vector<uint8_t> &key, SecurityManager::SecurityContent &content);
73 bool Decrypt(const SecurityManager::SecurityContent &content, std::vector<uint8_t> &key);
74 static void DeleteKVStore();
75
76 static std::vector<uint8_t> vecRootKeyAlias_;
77 static std::vector<uint8_t> vecAad_;
78 };
79
80 std::vector<uint8_t> StoreFactoryTest::vecRootKeyAlias_ =
81 std::vector<uint8_t>(ROOT_KEY_ALIAS, ROOT_KEY_ALIAS + strlen(ROOT_KEY_ALIAS));
82 std::vector<uint8_t> StoreFactoryTest::vecAad_ =
83 std::vector<uint8_t>(HKS_BLOB_TYPE_AAD, HKS_BLOB_TYPE_AAD + strlen(HKS_BLOB_TYPE_AAD));
84
SetUpTestCase(void)85 void StoreFactoryTest::SetUpTestCase(void) { }
86
TearDownTestCase(void)87 void StoreFactoryTest::TearDownTestCase(void) { }
88
SetUp(void)89 void StoreFactoryTest::SetUp(void)
90 {
91 std::string baseDir = "/data/service/el1/public/database/rekey";
92 mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH));
93 }
94
TearDown(void)95 void StoreFactoryTest::TearDown(void)
96 {
97 DeleteKVStore();
98 (void)remove("/data/service/el1/public/database/rekey");
99 }
100
DeleteKVStore()101 void StoreFactoryTest::DeleteKVStore()
102 {
103 StoreManager::GetInstance().Delete(appId, storeId, options.baseDir);
104 }
105
Encrypt(const std::vector<uint8_t> & key,SecurityManager::SecurityContent & content)106 bool StoreFactoryTest::Encrypt(const std::vector<uint8_t> &key, SecurityManager::SecurityContent &content)
107 {
108 struct HksParamSet *params = nullptr;
109 int32_t ret = HksInitParamSet(¶ms);
110 if (ret != HKS_SUCCESS) {
111 return false;
112 }
113
114 uint8_t nonceValue[SecurityManager::SecurityContent::NONCE_SIZE] = {0};
115 struct HksBlob blobNonce = { .size = SecurityManager::SecurityContent::NONCE_SIZE, .data = nonceValue };
116 ret = HksGenerateRandom(nullptr, &blobNonce);
117 if (ret != HKS_SUCCESS) {
118 return false;
119 }
120
121 struct HksBlob blobAad = { uint32_t(vecAad_.size()), vecAad_.data() };
122 struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() };
123 struct HksBlob plainKey = { uint32_t(key.size()), const_cast<uint8_t *>(key.data()) };
124 struct HksParam hksParam[] = {
125 { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
126 { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT },
127 { .tag = HKS_TAG_DIGEST, .uint32Param = 0 },
128 { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
129 { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE },
130 { .tag = HKS_TAG_NONCE, .blob = blobNonce },
131 { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad },
132 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE },
133 };
134 ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0]));
135 if (ret != HKS_SUCCESS) {
136 HksFreeParamSet(¶ms);
137 return false;
138 }
139
140 ret = HksBuildParamSet(¶ms);
141 if (ret != HKS_SUCCESS) {
142 HksFreeParamSet(¶ms);
143 return false;
144 }
145
146 uint8_t cipherBuf[256] = { 0 };
147 struct HksBlob cipherText = { sizeof(cipherBuf), cipherBuf };
148 ret = HksEncrypt(&rootKeyName, params, &plainKey, &cipherText);
149 (void)HksFreeParamSet(¶ms);
150 if (ret != HKS_SUCCESS) {
151 return false;
152 }
153 std::vector<uint8_t> nonceContent(blobNonce.data, blobNonce.data + blobNonce.size);
154 content.nonceValue = nonceContent;
155 std::vector<uint8_t> encryptValue(cipherText.data, cipherText.data + cipherText.size);
156 content.encryptValue = encryptValue;
157 std::fill(cipherBuf, cipherBuf + sizeof(cipherBuf), 0);
158 return true;
159 }
160
Decrypt(const SecurityManager::SecurityContent & content,std::vector<uint8_t> & key)161 bool StoreFactoryTest::Decrypt(const SecurityManager::SecurityContent &content, std::vector<uint8_t> &key)
162 {
163 struct HksParamSet *params = nullptr;
164 int32_t ret = HksInitParamSet(¶ms);
165 if (ret != HKS_SUCCESS) {
166 return false;
167 }
168
169 struct HksBlob blobNonce = { .size = uint32_t(content.nonceValue.size()),
170 .data = const_cast<uint8_t*>(&(content.nonceValue[0])) };
171 struct HksBlob blobAad = { uint32_t(vecAad_.size()), &(vecAad_[0]) };
172 struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), &(vecRootKeyAlias_[0]) };
173 struct HksBlob encryptedKeyBlob = { uint32_t(content.encryptValue.size()),
174 const_cast<uint8_t *>(content.encryptValue.data()) };
175 struct HksParam hksParam[] = {
176 { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
177 { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT },
178 { .tag = HKS_TAG_DIGEST, .uint32Param = 0 },
179 { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
180 { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE },
181 { .tag = HKS_TAG_NONCE, .blob = blobNonce },
182 { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad },
183 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE },
184 };
185 ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0]));
186 if (ret != HKS_SUCCESS) {
187 HksFreeParamSet(¶ms);
188 return false;
189 }
190
191 ret = HksBuildParamSet(¶ms);
192 if (ret != HKS_SUCCESS) {
193 HksFreeParamSet(¶ms);
194 return false;
195 }
196
197 uint8_t plainBuf[256] = { 0 };
198 struct HksBlob plainKeyBlob = { sizeof(plainBuf), plainBuf };
199 ret = HksDecrypt(&rootKeyName, params, &encryptedKeyBlob, &plainKeyBlob);
200 (void)HksFreeParamSet(¶ms);
201 if (ret != HKS_SUCCESS) {
202 return false;
203 }
204
205 key.assign(plainKeyBlob.data, plainKeyBlob.data + plainKeyBlob.size);
206 std::fill(plainBuf, plainBuf + sizeof(plainBuf), 0);
207 return true;
208 }
209
GetDate(const std::string & name,const std::string & path)210 std::chrono::system_clock::time_point StoreFactoryTest::GetDate(const std::string &name, const std::string &path)
211 {
212 std::chrono::system_clock::time_point timePoint;
213 auto keyPath = path + "/key/" + name + ".key_v1";
214 if (!OHOS::FileExists(keyPath)) {
215 return timePoint;
216 }
217 std::vector<char> content;
218 auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
219 if (!loaded) {
220 return timePoint;
221 }
222 SecurityManager::SecurityContent securityContent;
223 size_t offset = SecurityManager::SecurityContent::MAGIC_NUM;
224 securityContent.nonceValue.assign(content.begin() + offset,
225 content.begin() + offset + SecurityManager::SecurityContent::NONCE_SIZE);
226 offset += SecurityManager::SecurityContent::NONCE_SIZE;
227 securityContent.encryptValue.assign(content.begin() + offset, content.end());
228 std::vector<uint8_t> fullKey;
229 if (!Decrypt(securityContent, fullKey)) {
230 return timePoint;
231 }
232 offset = 0;
233 securityContent.version = fullKey[offset++];
234 securityContent.time.assign(fullKey.begin() + offset,
235 fullKey.begin() + offset + (sizeof(time_t) / sizeof(uint8_t)));
236 timePoint = std::chrono::system_clock::from_time_t(
237 *reinterpret_cast<time_t *>(const_cast<uint8_t *>(securityContent.time.data())));
238 return timePoint;
239 }
240
ChangeKeyDate(const std::string & name,const std::string & path,int duration,const std::vector<uint8_t> & key)241 bool StoreFactoryTest::ChangeKeyDate(const std::string &name, const std::string &path, int duration,
242 const std::vector<uint8_t> &key)
243 {
244 auto keyPath = path + "/key/" + name + ".key_v1";
245 if (!OHOS::FileExists(keyPath)) {
246 return false;
247 }
248 SecurityManager::SecurityContent securityContent;
249 securityContent.version = SecurityManager::SecurityContent::CURRENT_VERSION;
250 auto time = std::chrono::system_clock::to_time_t(
251 std::chrono::system_clock::system_clock::now() - std::chrono::hours(duration));
252 securityContent.time = { reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time) };
253 std::vector<uint8_t> keyContent;
254 keyContent.push_back(securityContent.version);
255 keyContent.insert(keyContent.end(), securityContent.time.begin(), securityContent.time.end());
256 keyContent.insert(keyContent.end(), key.begin(), key.end());
257 if (!Encrypt(keyContent, securityContent)) {
258 return false;
259 }
260 std::vector<char> content;
261 for (size_t index = 0; index < SecurityManager::SecurityContent::MAGIC_NUM; ++index) {
262 content.push_back(char(SecurityManager::SecurityContent::MAGIC_CHAR));
263 }
264 content.insert(content.end(), securityContent.nonceValue.begin(), securityContent.nonceValue.end());
265 content.insert(content.end(), securityContent.encryptValue.begin(), securityContent.encryptValue.end());
266 return OHOS::SaveBufferToFile(keyPath, content);
267 }
268
MoveToRekeyPath(Options options,StoreId storeId)269 bool StoreFactoryTest::MoveToRekeyPath(Options options, StoreId storeId)
270 {
271 std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key_v1";
272 std::string rekeyFileName = options.baseDir + "/rekey/key/" + storeId.storeId + ".new.key_v1";
273 bool result = StoreUtil::Rename(keyFileName, rekeyFileName);
274 if (!result) {
275 return false;
276 }
277 result = StoreUtil::Remove(keyFileName);
278 return result;
279 }
280
GetDBManager(const std::string & path,const AppId & appId)281 std::shared_ptr<StoreFactoryTest::DBManager> StoreFactoryTest::GetDBManager(const std::string &path, const AppId &appId)
282 {
283 std::string fullPath = path + "/kvdb";
284 StoreUtil::InitPath(fullPath);
285 std::shared_ptr<DBManager> dbManager = std::make_shared<DBManager>(appId.appId, "default");
286 dbManager->SetKvStoreConfig({ fullPath });
287 BackupManager::GetInstance().Init(path);
288 return dbManager;
289 }
290
GetOption(const Options & options,const DBPassword & dbPassword)291 StoreFactoryTest::DBOption StoreFactoryTest::GetOption(const Options &options, const DBPassword &dbPassword)
292 {
293 DBOption dbOption;
294 dbOption.syncDualTupleMode = true; // tuple of (appid+storeid)
295 dbOption.createIfNecessary = options.createIfMissing;
296 dbOption.isNeedRmCorruptedDb = options.rebuild;
297 dbOption.isMemoryDb = (!options.persistent);
298 dbOption.isEncryptedDb = options.encrypt;
299 if (options.encrypt) {
300 dbOption.cipher = DistributedDB::CipherType::AES_256_GCM;
301 dbOption.passwd = dbPassword.password;
302 }
303
304 dbOption.conflictResolvePolicy = options.kvStoreType == KvStoreType::SINGLE_VERSION ?
305 DistributedDB::LAST_WIN :
306 DistributedDB::DEVICE_COLLABORATION;
307
308 dbOption.schema = options.schema;
309 dbOption.createDirByStoreIdOnly = true;
310 dbOption.secOption = StoreUtil::GetDBSecurity(options.securityLevel);
311 return dbOption;
312 }
313
ChangeKVStoreDate(const std::string & storeId,std::shared_ptr<DBManager> dbManager,const Options & options,DBPassword & dbPassword,int time)314 StoreFactoryTest::DBStatus StoreFactoryTest::ChangeKVStoreDate(const std::string &storeId,
315 std::shared_ptr<DBManager> dbManager, const Options &options, DBPassword &dbPassword, int time)
316 {
317 DBStatus status;
318 const auto dbOption = GetOption(options, dbPassword);
319 DBStore *store = nullptr;
320 dbManager->GetKvStore(storeId, dbOption, [&status, &store](auto dbStatus, auto *dbStore) {
321 status = dbStatus;
322 store = dbStore;
323 });
324 dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
325 std::vector<uint8_t> key(dbPassword.GetData(), dbPassword.GetData() + dbPassword.GetSize());
326 if (!ChangeKeyDate(storeId, options.baseDir, time, key)) {
327 std::cout << "failed" << std::endl;
328 }
329 dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
330 auto dbStatus = store->Rekey(dbPassword.password);
331 dbManager->CloseKvStore(store);
332 return dbStatus;
333 }
334
ModifyDate(int time)335 bool StoreFactoryTest::ModifyDate(int time)
336 {
337 auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
338 auto dbManager = GetDBManager(options.baseDir, appId);
339 auto dbstatus = ChangeKVStoreDate(storeId, dbManager, options, dbPassword, time);
340 return StoreUtil::ConvertStatus(dbstatus) == SUCCESS;
341 }
342
343 /**
344 * @tc.name: Rekey
345 * @tc.desc: test rekey function
346 * @tc.type: FUNC
347 * @tc.require:
348 * @tc.author: Cui Renjie
349 */
350 HWTEST_F(StoreFactoryTest, Rekey, TestSize.Level1)
351 {
352 Status status = DB_ERROR;
353 options.autoRekey = true;
354 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
355 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
356 ASSERT_EQ(status, SUCCESS);
357
358 ASSERT_TRUE(ModifyDate(OUTDATED_TIME));
359
360 auto oldKeyTime = GetDate(storeId, options.baseDir);
361 ASSERT_FALSE(std::chrono::system_clock::now() - oldKeyTime < std::chrono::seconds(2));
362
363 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
364 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
365 ASSERT_EQ(status, SUCCESS);
366
367 auto newKeyTime = GetDate(storeId, options.baseDir);
368 ASSERT_TRUE(std::chrono::system_clock::now() - newKeyTime < std::chrono::seconds(2));
369 }
370
371 /**
372 * @tc.name: RekeyNotOutdated
373 * @tc.desc: try to rekey kvstore with not outdated password
374 * @tc.type: FUNC
375 * @tc.require:
376 * @tc.author: Cui Renjie
377 */
378 HWTEST_F(StoreFactoryTest, RekeyNotOutdated, TestSize.Level1)
379 {
380 Status status = DB_ERROR;
381 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
382 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
383 ASSERT_EQ(status, SUCCESS);
384
385 ASSERT_TRUE(ModifyDate(NOT_OUTDATED_TIME));
386 auto oldKeyTime = GetDate(storeId, options.baseDir);
387
388 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
389 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
390 ASSERT_EQ(status, SUCCESS);
391
392 auto newKeyTime = GetDate(storeId, options.baseDir);
393 ASSERT_EQ(oldKeyTime, newKeyTime);
394 }
395
396 /**
397 * @tc.name: RekeyInterrupted0
398 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
399 * which caused key file lost but rekey key file exist.
400 * @tc.type: FUNC
401 * @tc.require:
402 * @tc.author: Cui Renjie
403 */
404 HWTEST_F(StoreFactoryTest, RekeyInterruptedWhileChangeKeyFile, TestSize.Level1)
405 {
406 Status status = DB_ERROR;
407 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
408 ASSERT_EQ(status, SUCCESS);
409 auto oldKeyTime = GetDate(storeId, options.baseDir);
410
411 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
412 ASSERT_EQ(status, SUCCESS);
413 ASSERT_TRUE(MoveToRekeyPath(options, storeId));
414
415 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
416 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
417 ASSERT_EQ(status, SUCCESS);
418 std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key_v1";
419 auto isKeyExist = StoreUtil::IsFileExist(keyFileName);
420 ASSERT_TRUE(isKeyExist);
421
422 auto newKeyTime = GetDate(storeId, options.baseDir);
423 ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
424 }
425
426 /**
427 * @tc.name: RekeyInterrupted1
428 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
429 * which caused key file not changed but rekey key file exist.
430 * @tc.type: FUNC
431 * @tc.require:
432 * @tc.author: Cui Renjie
433 */
434 HWTEST_F(StoreFactoryTest, RekeyInterruptedBeforeChangeKeyFile, TestSize.Level1)
435 {
436 Status status = DB_ERROR;
437 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
438 ASSERT_EQ(status, SUCCESS);
439 auto oldKeyTime = GetDate(storeId, options.baseDir);
440
441 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
442 ASSERT_EQ(status, SUCCESS);
443 ASSERT_EQ(MoveToRekeyPath(options, storeId), true);
444
445 StoreId newStoreId = { "newStore" };
446 StoreManager::GetInstance().GetKVStore(appId, newStoreId, options, status);
447
448 std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key_v1";
449 std::string mockKeyFileName = options.baseDir + "/key/" + newStoreId.storeId + ".key_v1";
450 StoreUtil::Rename(mockKeyFileName, keyFileName);
451 StoreUtil::Remove(mockKeyFileName);
452 auto isKeyExist = StoreUtil::IsFileExist(mockKeyFileName);
453 ASSERT_FALSE(isKeyExist);
454 isKeyExist = StoreUtil::IsFileExist(keyFileName);
455 ASSERT_TRUE(isKeyExist);
456
457 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
458 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
459 ASSERT_EQ(status, SUCCESS);
460
461 isKeyExist = StoreUtil::IsFileExist(keyFileName);
462 ASSERT_TRUE(isKeyExist);
463
464 auto newKeyTime = GetDate(storeId, options.baseDir);
465 ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
466 }
467
468 /**
469 * @tc.name: RekeyNoPwdFile
470 * @tc.desc: try to open kvstore and execute RekeyRecover() without key and rekey key files.
471 * @tc.type: FUNC
472 * @tc.require:
473 * @tc.author: Cui Renjie
474 */
475 HWTEST_F(StoreFactoryTest, RekeyNoPwdFile, TestSize.Level1)
476 {
477 Status status = DB_ERROR;
478 options.autoRekey = false;
479 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
480 ASSERT_EQ(status, SUCCESS);
481
482 status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
483 ASSERT_EQ(status, SUCCESS);
484 std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key_v1";
485 StoreUtil::Remove(keyFileName);
486
487 auto isKeyExist = StoreUtil::IsFileExist(keyFileName);
488 ASSERT_EQ(isKeyExist, false);
489
490 StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
491 ASSERT_EQ(status, SUCCESS);
492
493 isKeyExist = StoreUtil::IsFileExist(keyFileName);
494 ASSERT_EQ(isKeyExist, true);
495 }
496 } // namespace