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 #ifndef OMIT_JSON
17 #include <cstdint>
18 #include <gtest/gtest.h>
19 #include "db_common.h"
20 #include "db_constant.h"
21 #include "distributeddb_tools_unit_test.h"
22 #include "query.h"
23 #include "schema_constant.h"
24 #include "schema_utils.h"
25 #include "sqlite_import.h"
26 #include "sqlite_local_kvdb_connection.h"
27
28 using namespace testing::ext;
29 using namespace DistributedDB;
30 using namespace DistributedDBUnitTest;
31 using namespace std;
32
33 namespace {
34 // Directory and delegate related
35 string g_testDir;
36 KvStoreConfig g_config;
37 const string USER_NAME = "TEST0";
38 const string APP_NAME = "OHOS";
39 KvStoreDelegateManager g_mgr(APP_NAME, USER_NAME);
40 DBStatus g_kvDelegateStatus = INVALID_ARGS;
41 KvStoreNbDelegate *g_kvNbDelegatePtr = nullptr;
42 DBStatus g_kvDelegateStatus2 = INVALID_ARGS;
43 KvStoreNbDelegate *g_kvNbDelegatePtr2 = nullptr;
44 auto g_kvNbDelegateCallback = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback,
45 placeholders::_1, placeholders::_2, std::ref(g_kvDelegateStatus), std::ref(g_kvNbDelegatePtr));
46 auto g_kvNbDelegateCallback2 = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback,
47 placeholders::_1, placeholders::_2, std::ref(g_kvDelegateStatus2), std::ref(g_kvNbDelegatePtr2));
48
GetKvStoreDirectory(const string & storeId,int databaseType)49 string GetKvStoreDirectory(const string &storeId, int databaseType)
50 {
51 string identifier = USER_NAME + "-" + APP_NAME + "-" + storeId;
52 string hashIdentifierName = DBCommon::TransferHashString(identifier);
53 string identifierName = DBCommon::TransferStringToHex(hashIdentifierName);
54 string filePath = g_testDir + "/" + identifierName + "/";
55 if (databaseType == DBConstant::DB_TYPE_LOCAL) { // local
56 filePath += (DBConstant::LOCAL_SUB_DIR + "/" + DBConstant::LOCAL_DATABASE_NAME +
57 DBConstant::DB_EXTENSION);
58 } else if (databaseType == DBConstant::DB_TYPE_SINGLE_VER) { // single ver
59 filePath += (DBConstant::SINGLE_SUB_DIR + "/" + DBConstant::MAINDB_DIR + "/" +
60 DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION);
61 } else if (databaseType == DBConstant::DB_TYPE_MULTI_VER) { // multi ver
62 filePath += (DBConstant::MULTI_SUB_DIR + "/" + DBConstant::MULTI_VER_DATA_STORE +
63 DBConstant::DB_EXTENSION);
64 } else {
65 filePath = "";
66 }
67
68 return filePath;
69 }
70
71 // Query sqlite_master related
72 const string SQL_QUERY_INDEX = "SELECT COUNT(*) FROM sqlite_master where type = 'index' and name = ";
CallbackReturnCount(void * data,int argc,char ** argv,char ** azColName)73 int CallbackReturnCount(void *data, int argc, char **argv, char **azColName)
74 {
75 if (argc == 1) {
76 int count = strtol(*(argv), nullptr, 10); // 10: decimal
77 if (data != nullptr) {
78 int *mid = static_cast<int *>(data);
79 *mid = count;
80 }
81 }
82 return 0;
83 }
84
85 // Schema and value info related
GenerateFieldName(uint32_t serial,uint32_t level,bool fullLength)86 FieldName GenerateFieldName(uint32_t serial, uint32_t level, bool fullLength)
87 {
88 FieldName result = "Serial_";
89 result += to_string(serial);
90 result += "_Level_";
91 result += to_string(level);
92 if (fullLength) {
93 while (result.size() < SchemaConstant::SCHEMA_FEILD_NAME_LENGTH_MAX) {
94 result.push_back('_');
95 }
96 }
97 return result;
98 }
99
GenerateFieldPath(uint32_t totalLevel,uint32_t serial,bool fullLength)100 FieldPath GenerateFieldPath(uint32_t totalLevel, uint32_t serial, bool fullLength)
101 {
102 FieldPath result;
103 for (uint32_t level = 0; level < totalLevel; level++) {
104 string fieldName = GenerateFieldName(serial, level, fullLength);
105 result.push_back(fieldName);
106 }
107 return result;
108 }
109
GenerateSchemaIndexArray(const vector<FieldPath> & indexAll)110 string GenerateSchemaIndexArray(const vector<FieldPath> &indexAll)
111 {
112 string result = "[";
113 for (auto &entry : indexAll) {
114 result += "\"";
115 result += SchemaUtils::FieldPathString(entry);
116 result += "\",";
117 }
118 if (!indexAll.empty()) {
119 result.pop_back();
120 }
121 result += "]";
122 return result;
123 }
124
GenerateEachSchemaDefine(const FieldPath & eachPath)125 string GenerateEachSchemaDefine(const FieldPath &eachPath)
126 {
127 string result;
128 for (auto iter = eachPath.rbegin(); iter != eachPath.rend(); iter++) {
129 if (result.empty()) {
130 result = string("\"") + *iter + "\":\"INTEGER\"";
131 } else {
132 result = string("\"") + *iter + "\":{" + result + "}";
133 }
134 }
135 return result;
136 }
137
GenerateSchemaString(const vector<FieldPath> & define,const vector<FieldPath> & index,int skipSize,bool hasIndex,bool hasSkipSize)138 string GenerateSchemaString(const vector<FieldPath> &define, const vector<FieldPath> &index, int skipSize,
139 bool hasIndex, bool hasSkipSize)
140 {
141 string result = "{\"SCHEMA_VERSION\":\"1.0\",\"SCHEMA_MODE\":\"STRICT\",\"SCHEMA_DEFINE\":{";
142 for (const auto &entry : define) {
143 string defineStr = GenerateEachSchemaDefine(entry);
144 result += defineStr;
145 result += ",";
146 }
147 if (!define.empty()) {
148 result.pop_back();
149 }
150 result += "}";
151 if (hasIndex) {
152 result += ",\"SCHEMA_INDEXES\":";
153 result += GenerateSchemaIndexArray(index);
154 }
155 if (hasSkipSize) {
156 result += ",\"SCHEMA_SKIPSIZE\":";
157 result += to_string(skipSize);
158 }
159 result += "}";
160 return result;
161 }
162
GenerateValueItem(const FieldPath & eachPath,int intValue)163 string GenerateValueItem(const FieldPath &eachPath, int intValue)
164 {
165 string result;
166 for (auto iter = eachPath.rbegin(); iter != eachPath.rend(); iter++) {
167 if (result.empty()) {
168 result = string("\"") + *iter + "\":" + to_string(intValue);
169 } else {
170 result = string("\"") + *iter + "\":{" + result + "}";
171 }
172 }
173 return result;
174 }
GenerateValue(const vector<FieldPath> & define,uint32_t skipSize)175 string GenerateValue(const vector<FieldPath> &define, uint32_t skipSize)
176 {
177 int intValue = 0;
178 string result(skipSize, '*');
179 result += "{";
180 for (const auto &entry : define) {
181 string defineStr = GenerateValueItem(entry, intValue++);
182 result += defineStr;
183 result += ",";
184 }
185 if (!define.empty()) {
186 result.pop_back();
187 }
188 result += "}";
189 return result;
190 }
191
192 vector<FieldPath> g_pathGroup1;
193 vector<FieldPath> g_pathGroup2;
194 vector<string> g_pathStrGroup1;
195 vector<string> g_pathStrGroup2;
196 vector<FieldPath> g_definePath;
197 string g_schemaString1;
198 string g_schemaString2;
199 string g_valueString1;
200 string g_valueString2;
201
ResetGlobalVariable()202 void ResetGlobalVariable()
203 {
204 g_pathGroup1.clear();
205 g_pathGroup2.clear();
206 g_pathStrGroup1.clear();
207 g_pathStrGroup2.clear();
208 g_definePath.clear();
209 g_schemaString1.clear();
210 g_schemaString2.clear();
211 g_valueString1.clear();
212 g_valueString2.clear();
213 }
214
PrepareCommonInfo(bool fullLength)215 void PrepareCommonInfo(bool fullLength)
216 {
217 int serial = 0;
218 for (uint32_t level = 1; level <= SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; level++) {
219 FieldPath path = GenerateFieldPath(level, serial, fullLength);
220 string pathStr = SchemaUtils::FieldPathString(path);
221 g_pathGroup1.push_back(path);
222 g_pathStrGroup1.push_back(pathStr);
223 serial++;
224 }
225 for (uint32_t level = 1; level <= SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; level++) {
226 FieldPath path = GenerateFieldPath(level, serial, fullLength);
227 string pathStr = SchemaUtils::FieldPathString(path);
228 g_pathGroup2.push_back(path);
229 g_pathStrGroup2.push_back(pathStr);
230 serial++;
231 }
232 }
233
CheckIndexFromDbFile(sqlite3 * db,const vector<string> & indexToCheck,int expectCount)234 inline void CheckIndexFromDbFile(sqlite3 *db, const vector<string> &indexToCheck, int expectCount)
235 {
236 for (const auto &str : indexToCheck) {
237 string querySeq = SQL_QUERY_INDEX + "'" + str + "'";
238 int count = -1;
239 EXPECT_EQ(sqlite3_exec(db, querySeq.c_str(), CallbackReturnCount, &count, nullptr), SQLITE_OK);
240 EXPECT_EQ(count, expectCount);
241 }
242 }
243 }
244
245 class DistributedDBInterfacesIndexUnitTest : public testing::Test {
246 public:
247 static void SetUpTestCase(void);
248 static void TearDownTestCase(void);
249 void SetUp();
TearDown()250 void TearDown() {};
251 };
252
SetUpTestCase(void)253 void DistributedDBInterfacesIndexUnitTest::SetUpTestCase(void)
254 {
255 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
256 g_config.dataDir = g_testDir;
257 g_mgr.SetKvStoreConfig(g_config);
258 }
259
TearDownTestCase(void)260 void DistributedDBInterfacesIndexUnitTest::TearDownTestCase(void)
261 {
262 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
263 LOGE("[TestSuiteTearDown] rm test db files error!");
264 }
265 }
266
SetUp()267 void DistributedDBInterfacesIndexUnitTest::SetUp()
268 {
269 DistributedDBToolsUnitTest::PrintTestCaseInfo();
270 }
271
272 namespace {
PrepareInfoForCrudIndex001()273 void PrepareInfoForCrudIndex001()
274 {
275 PrepareCommonInfo(false);
276 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
277 g_definePath.insert(g_definePath.end(), g_pathGroup2.begin(), g_pathGroup2.end());
278 g_schemaString1 = GenerateSchemaString(g_definePath, g_pathGroup1, 0, true, false);
279 g_schemaString2 = GenerateSchemaString(g_definePath, g_definePath, 0, true, false);
280 LOGI("[PrepareInfoForCrudIndex001] g_schemaString1=%s", g_schemaString1.c_str());
281 LOGI("[PrepareInfoForCrudIndex001] g_schemaString2=%s", g_schemaString2.c_str());
282 }
283 }
284 /**
285 * @tc.name: CrudIndex001
286 * @tc.desc: Test whether adding index is normal
287 * @tc.type: FUNC
288 * @tc.require: AR000DR9K8
289 * @tc.author: yiguang
290 */
291 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CrudIndex001, TestSize.Level1)
292 {
293 PrepareInfoForCrudIndex001();
294 sqlite3 *db = nullptr;
295 string storeId = "CrudIndex001";
296 string filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
297 KvStoreNbDelegate::Option option = {true, false, false};
298 /**
299 * @tc.steps:step1. Specify the schema containing all levels of index to open the schema mode database.
300 * @tc.expected: step1. return OK.
301 */
302 option.schema = g_schemaString1;
303 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
304 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
305 EXPECT_EQ(g_kvDelegateStatus, OK);
306 /**
307 * @tc.steps:step2. Use the sql statement to get the count of the following index fields that will be added.
308 * @tc.expected: step2. count == 0.
309 */
310 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
311 CheckIndexFromDbFile(db, g_pathStrGroup2, 0);
312 sqlite3_close(db);
313 /**
314 * @tc.steps:step3. Close the database.
315 * @tc.expected: step3. return OK.
316 */
317 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
318 /**
319 * @tc.steps:step4. The original schema adds the above index fields,
320 * generates a new schema and opens the database with this schema.
321 * @tc.expected: step4. return OK.
322 */
323 option.schema = g_schemaString2;
324 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
325 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
326 EXPECT_EQ(g_kvDelegateStatus, OK);
327 /**
328 * @tc.steps:step5. Use the sql statement to get the count of the following index fields that are added.
329 * @tc.expected: step5. count == 1.
330 */
331 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
332 CheckIndexFromDbFile(db, g_pathStrGroup2, 1);
333 sqlite3_close(db);
334 // Clear
335 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
336 EXPECT_EQ(g_mgr.DeleteKvStore("CrudIndex001"), OK);
337 ResetGlobalVariable();
338 }
339
340 namespace {
PrepareInfoForCrudIndex002()341 void PrepareInfoForCrudIndex002()
342 {
343 PrepareCommonInfo(false);
344 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
345 g_schemaString1 = GenerateSchemaString(g_definePath, g_pathGroup1, 0, true, false);
346 g_schemaString2 = GenerateSchemaString(g_definePath, vector<FieldPath>(), 0, true, false);
347 LOGI("[PrepareInfoForCrudIndex002] g_schemaString1=%s", g_schemaString1.c_str());
348 LOGI("[PrepareInfoForCrudIndex002] g_schemaString2=%s", g_schemaString2.c_str());
349 }
350 }
351 /**
352 * @tc.name: CrudIndex002
353 * @tc.desc: Test whether deleting index is normal
354 * @tc.type: FUNC
355 * @tc.require: AR000DR9K8
356 * @tc.author: yiguang
357 */
358 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CrudIndex002, TestSize.Level1)
359 {
360 PrepareInfoForCrudIndex002();
361 sqlite3 *db = nullptr;
362 string storeId = "CrudIndex002";
363 string filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
364 KvStoreNbDelegate::Option option = {true, false, false};
365 /**
366 * @tc.steps:step1. Specify the schema containing all levels of index to open the schema mode database.
367 * @tc.expected: step1. return OK.
368 */
369 option.schema = g_schemaString1;
370 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
371 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
372 EXPECT_EQ(g_kvDelegateStatus, OK);
373 /**
374 * @tc.steps:step2. Use the sql statement to get the count of the following index fields that will be deleted.
375 * @tc.expected: step2. count == 1.
376 */
377 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
378 CheckIndexFromDbFile(db, g_pathStrGroup1, 1);
379 sqlite3_close(db);
380 /**
381 * @tc.steps:step3. Close the database.
382 * @tc.expected: step3. return OK.
383 */
384 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
385 /**
386 * @tc.steps:step4. The original schema delete the above index fields,
387 * generates a new schema and opens the database with this schema.
388 * @tc.expected: step4. return OK.
389 */
390 option.schema = g_schemaString2;
391 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
392 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
393 EXPECT_EQ(g_kvDelegateStatus, OK);
394 /**
395 * @tc.steps:step5. Use the sql statement to get the count of the following index fields that are deleted.
396 * @tc.expected: step5. count == 0.
397 */
398 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
399 CheckIndexFromDbFile(db, g_pathStrGroup1, 0);
400 sqlite3_close(db);
401 // Clear
402 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
403 EXPECT_EQ(g_mgr.DeleteKvStore("CrudIndex002"), OK);
404 ResetGlobalVariable();
405 }
406
407 namespace {
PrepareInfoForCrudIndex003()408 void PrepareInfoForCrudIndex003()
409 {
410 PrepareCommonInfo(false);
411 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
412 g_definePath.insert(g_definePath.end(), g_pathGroup2.begin(), g_pathGroup2.end());
413 g_schemaString1 = GenerateSchemaString(g_definePath, g_pathGroup1, 0, true, false);
414 g_schemaString2 = GenerateSchemaString(g_definePath, g_pathGroup2, 0, true, false);
415 LOGI("[PrepareInfoForCrudIndex003] g_schemaString1=%s", g_schemaString1.c_str());
416 LOGI("[PrepareInfoForCrudIndex003] g_schemaString2=%s", g_schemaString2.c_str());
417 }
418 }
419 /**
420 * @tc.name: CrudIndex003
421 * @tc.desc: Test whether updating index is normal
422 * @tc.type: FUNC
423 * @tc.require: AR000DR9K8
424 * @tc.author: yiguang
425 */
426 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CrudIndex003, TestSize.Level1)
427 {
428 PrepareInfoForCrudIndex003();
429 sqlite3 *db = nullptr;
430 string storeId = "CrudIndex003";
431 string filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
432 KvStoreNbDelegate::Option option = {true, false, false};
433 /**
434 * @tc.steps:step1. Specify the schema containing all levels of index to open the schema mode database.
435 * @tc.expected: step1. return OK.
436 */
437 option.schema = g_schemaString1;
438 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
439 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
440 EXPECT_EQ(g_kvDelegateStatus, OK);
441 /**
442 * @tc.steps:step2. Use the sql statement to get the count of the following index fields that will be deleted.
443 * @tc.expected: step2. count == 1.
444 */
445 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
446 CheckIndexFromDbFile(db, g_pathStrGroup1, 1);
447 /**
448 * @tc.steps:step3. Use the sql statement to get the count of the following index fields that will be added.
449 * @tc.expected: step3. count == 0.
450 */
451 CheckIndexFromDbFile(db, g_pathStrGroup2, 0);
452 sqlite3_close(db);
453 /**
454 * @tc.steps:step3. Close the database.
455 * @tc.expected: step3. return OK.
456 */
457 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
458 /**
459 * @tc.steps:step4. The original schema update the above index fields,
460 * generates a new schema and opens the database with this schema.
461 * @tc.expected: step4. return OK.
462 */
463 option.schema = g_schemaString2;
464 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
465 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
466 EXPECT_EQ(g_kvDelegateStatus, OK);
467 /**
468 * @tc.steps:step5. Use the sql statement to get the count of the following index fields that are deleted.
469 * @tc.expected: step5. count == 0.
470 */
471 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
472 CheckIndexFromDbFile(db, g_pathStrGroup1, 0);
473 /**
474 * @tc.steps:step5. Use the sql statement to get the count of the following index fields that are added.
475 * @tc.expected: step5. count == 1.
476 */
477 CheckIndexFromDbFile(db, g_pathStrGroup2, 1);
478 sqlite3_close(db);
479 // Clear
480 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
481 EXPECT_EQ(g_mgr.DeleteKvStore("CrudIndex003"), OK);
482 ResetGlobalVariable();
483 }
484
485 namespace {
PrepareInfoForCreateIndex001()486 void PrepareInfoForCreateIndex001()
487 {
488 PrepareCommonInfo(true);
489 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
490 g_schemaString1 = GenerateSchemaString(g_definePath, g_definePath, 8, true, true); // skipsize 8 in schema
491 g_valueString1 = GenerateValue(g_definePath, 8); // skipsize 8 in value
492 g_valueString2 = GenerateValue(g_definePath, 10); // skipsize 10 in value
493 LOGI("[PrepareInfoForCreateIndex001] g_schemaString1=%s", g_schemaString1.c_str());
494 LOGI("[PrepareInfoForCreateIndex001] g_valueString1=%s", g_valueString1.c_str());
495 LOGI("[PrepareInfoForCreateIndex001] g_valueString2=%s", g_valueString2.c_str());
496 }
497 }
498 /**
499 * @tc.name: CreateIndex001
500 * @tc.desc: Test whether the index creation is normal
501 * @tc.type: FUNC
502 * @tc.require: AR000DR9K9
503 * @tc.author: yiguang
504 */
505 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CreateIndex001, TestSize.Level1)
506 {
507 PrepareInfoForCreateIndex001();
508 sqlite3 *db = nullptr;
509 string storeId = "CreateIndex001";
510 string filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
511 KvStoreNbDelegate::Option option = {true, false, false};
512 /**
513 * @tc.steps:step1. Specify the schema containing all levels of index to open the schema mode database.
514 * The four-level index has 64 bytes per field.
515 * @tc.expected: step1. return OK.
516 */
517 option.schema = g_schemaString1;
518 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
519 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
520 EXPECT_EQ(g_kvDelegateStatus, OK);
521 /**
522 * @tc.steps:step2. Use the sql statement to get each index count count from the table;
523 * @tc.expected: step2. count == 1.
524 */
525 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
526 CheckIndexFromDbFile(db, g_pathStrGroup1, 1);
527 sqlite3_close(db);
528 /**
529 * @tc.steps:step3. Write a value with 8 prefix bytes and the json part strictly conforms
530 * to the value of the schema. Call the query interface to query the inserted data.
531 * @tc.expected: step3. The insertion is successful and the number of entries obtained by the query is 1.
532 */
533 Key key001{'1'};
534 Value value001(g_valueString1.begin(), g_valueString1.end());
535 EXPECT_EQ(g_kvNbDelegatePtr->Put(key001, value001), OK);
536 Query query = Query::Select().GreaterThanOrEqualTo(g_pathStrGroup1.front(), 0);
537 vector<Entry> entries;
538 EXPECT_EQ(g_kvNbDelegatePtr->GetEntries(query, entries), OK);
539 EXPECT_EQ(entries.size(), 1ul);
540 /**
541 * @tc.steps:step4. Write a value with 10 prefix bytes and the json part strictly conforms
542 * to the value of the schema.
543 * @tc.expected: step4. The insertion is failed.
544 */
545 Key key002{'2'};
546 Value value002(g_valueString2.begin(), g_valueString2.end());
547 EXPECT_TRUE(g_kvNbDelegatePtr->Put(key002, value002) != OK);
548 // Clear
549 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
550 EXPECT_EQ(g_mgr.DeleteKvStore("CreateIndex001"), OK);
551 ResetGlobalVariable();
552 }
553
554 namespace {
PrepareInfoForCreateIndex002()555 void PrepareInfoForCreateIndex002()
556 {
557 for (uint32_t serial = 0; serial < SchemaConstant::SCHEMA_INDEX_COUNT_MAX; serial++) {
558 FieldPath path = GenerateFieldPath(SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX, serial, true);
559 string pathStr = SchemaUtils::FieldPathString(path);
560 g_pathGroup1.push_back(path);
561 g_pathStrGroup1.push_back(pathStr);
562 }
563 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
564 g_schemaString1 = GenerateSchemaString(g_definePath, g_definePath, 0, true, false);
565 LOGI("[PrepareInfoForCreateIndex002] g_schemaString1=%s", g_schemaString1.c_str());
566 }
567 }
568 /**
569 * @tc.name: CreateIndex002
570 * @tc.desc: Test whether it is possible to insert 32 four-level indexes with each filed being 64.
571 * @tc.type: FUNC
572 * @tc.require: AR000DR9K9
573 * @tc.author: yiguang
574 */
575 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CreateIndex002, TestSize.Level1)
576 {
577 PrepareInfoForCreateIndex002();
578 sqlite3 *db = nullptr;
579 string storeId = "CreateIndex002";
580 string filePath = GetKvStoreDirectory(storeId, DBConstant::DB_TYPE_SINGLE_VER);
581 KvStoreNbDelegate::Option option = {true, false, false};
582 /**
583 * @tc.steps:step1. Specifies that a schema with 32 four-level indexes
584 * with each filed being 64 opens the schema mode database
585 * @tc.expected: step1. return OK.
586 */
587 option.schema = g_schemaString1;
588 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
589 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
590 EXPECT_EQ(g_kvDelegateStatus, OK);
591 /**
592 * @tc.steps:step2. Use the sql statement to get each index count count from the table;
593 * @tc.expected: step2. count == 1.
594 */
595 EXPECT_EQ(sqlite3_open_v2(filePath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
596 CheckIndexFromDbFile(db, g_pathStrGroup1, 1);
597 sqlite3_close(db);
598 // Clear
599 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
600 EXPECT_EQ(g_mgr.DeleteKvStore("CreateIndex002"), OK);
601 ResetGlobalVariable();
602 }
603
604 namespace {
PrepareInfoForCheckSchemaSkipsize001()605 void PrepareInfoForCheckSchemaSkipsize001()
606 {
607 PrepareCommonInfo(false);
608 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
609 g_schemaString1 = GenerateSchemaString(g_definePath, g_pathGroup1, 0, true, false);
610 g_valueString1 = GenerateValue(g_definePath, 0);
611 g_valueString2 = GenerateValue(g_definePath, 8); // skipsize 8 in value
612 LOGI("[PrepareInfoForCheckSchemaSkipsize001] g_schemaString1=%s", g_schemaString1.c_str());
613 LOGI("[PrepareInfoForCheckSchemaSkipsize001] g_valueString1=%s", g_valueString1.c_str());
614 LOGI("[PrepareInfoForCheckSchemaSkipsize001] g_valueString2=%s", g_valueString2.c_str());
615 }
616 }
617 /**
618 * @tc.name: Check schema skipsize 001
619 * @tc.desc: When SCHEMA_SKIPSIZE is not defined, check if the default is 0
620 * @tc.type: FUNC
621 * @tc.require: AR000DR9K9
622 * @tc.author: yiguang
623 */
624 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CheckSchemaSkipsize001, TestSize.Level1)
625 {
626 PrepareInfoForCheckSchemaSkipsize001();
627 string storeId = "CheckSchemaSkipsize001";
628 KvStoreNbDelegate::Option option = {true, false, false};
629 /**
630 * @tc.steps:step1. Specify an undefined skipsize schema to open the schema database.
631 * @tc.expected: step1. return OK.
632 */
633 option.schema = g_schemaString1;
634 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
635 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
636 EXPECT_EQ(g_kvDelegateStatus, OK);
637 /**
638 * @tc.steps:step2. Write a value without prefix and strictly in accordance with the schema.
639 * @tc.expected: step2. return OK.
640 */
641 Key key001{'1'};
642 Value value001(g_valueString1.begin(), g_valueString1.end());
643 EXPECT_EQ(g_kvNbDelegatePtr->Put(key001, value001), OK);
644 /**
645 * @tc.steps:step3. Write a value whose prefix is 8 and strictly in accordance with the schema.
646 * @tc.expected: step3. return not OK.
647 */
648 Key key002{'2'};
649 Value value002(g_valueString2.begin(), g_valueString2.end());
650 EXPECT_TRUE(g_kvNbDelegatePtr->Put(key002, value002) != OK);
651 // Clear
652 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
653 EXPECT_EQ(g_mgr.DeleteKvStore("CheckSchemaSkipsize001"), OK);
654 ResetGlobalVariable();
655 }
656
657 /**
658 * @tc.name: Check schema skipsize 002
659 * @tc.desc: SCHEMA_SKIPSIZE range is [0,4MB-2]
660 * @tc.type: FUNC
661 * @tc.require: AR000DR9K9
662 * @tc.author: yiguang
663 */
664 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CheckSchemaSkipsize002, TestSize.Level1)
665 {
666 PrepareCommonInfo(false);
667 string storeId = "CheckSchemaSkipsize002";
668 KvStoreNbDelegate::Option option = {true, false, false};
669 /**
670 * @tc.steps:step1. Set "SCHEMA_SKIPSIZE" in the schema as -1 to create the schema database.
671 * @tc.expected: step1. return not OK.
672 */
673 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(), -1, false, true); // skipsize -1 in schema
674 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
675 EXPECT_TRUE(g_kvNbDelegatePtr == nullptr);
676 EXPECT_TRUE(g_kvDelegateStatus != OK);
677
678 /**
679 * @tc.steps:step2. Set "SCHEMA_SKIPSIZE" in the schema as 0 to create the schema database.
680 * @tc.expected: step2. return not OK.
681 */
682 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(), 0, false, true);
683 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
684 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
685 EXPECT_EQ(g_kvDelegateStatus, OK);
686 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
687 EXPECT_EQ(g_mgr.DeleteKvStore("CheckSchemaSkipsize002"), OK);
688
689 /**
690 * @tc.steps:step3. Set "SCHEMA_SKIPSIZE" in the schema as 8 to create the schema database.
691 * @tc.expected: step3. return OK.
692 */
693 option.schema = GenerateSchemaString(g_pathGroup1, g_pathGroup1, 8, true, true); // skipsize 8 in schema
694 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
695 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
696 EXPECT_EQ(g_kvDelegateStatus, OK);
697 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
698 EXPECT_EQ(g_mgr.DeleteKvStore("CheckSchemaSkipsize002"), OK);
699
700 /**
701 * @tc.steps:step4. Set "SCHEMA_SKIPSIZE" in the schema as 4MB-2 to create the schema database.
702 * @tc.expected: step6. return OK.
703 */
704 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(),
705 4 * 1024 * 1024 - 2, false, true); // skipsize in schema, 4M - 2, 1024 is scale
706 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
707 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
708 EXPECT_EQ(g_kvDelegateStatus, OK);
709 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
710 EXPECT_EQ(g_mgr.DeleteKvStore("CheckSchemaSkipsize002"), OK);
711
712 /**
713 * @tc.steps:step5. Set SCHEMA_SKIPSIZE in the schema as 4MB-1 to create the schema database.
714 * @tc.expected: step6. return not OK.
715 */
716 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(),
717 4 * 1024 * 1024 - 1, false, true); // skipsize in schema, 4M - 1, 1024 is scale
718 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
719 EXPECT_TRUE(g_kvNbDelegatePtr == nullptr);
720 EXPECT_TRUE(g_kvDelegateStatus != OK);
721 // Clear
722 ResetGlobalVariable();
723 }
724
725 namespace {
PrepareInfoForCheckSchemaSkipsize003()726 void PrepareInfoForCheckSchemaSkipsize003()
727 {
728 PrepareCommonInfo(false);
729 g_definePath.insert(g_definePath.end(), g_pathGroup1.begin(), g_pathGroup1.end());
730 g_schemaString1 = GenerateSchemaString(g_definePath, g_pathGroup1, 20, true, true); // skipsize 20 in schema
731 g_valueString1 = GenerateValue(g_definePath, 19); // skipsize 19 in value
732 g_valueString2 = GenerateValue(g_definePath, 20); // skipsize 20 in value
733 LOGI("[PrepareInfoForCheckSchemaSkipsize003] g_schemaString1=%s", g_schemaString1.c_str());
734 LOGI("[PrepareInfoForCheckSchemaSkipsize003] g_valueString1=%s", g_valueString1.c_str());
735 LOGI("[PrepareInfoForCheckSchemaSkipsize003] g_valueString2=%s", g_valueString2.c_str());
736 }
737 }
738 /**
739 * @tc.name: Check schema skipsize 003
740 * @tc.desc: When "SCHEMA_SKIPSIZE" is greater than or equal to the size of Value,
741 * the Value verification must fail
742 * @tc.type: FUNC
743 * @tc.require: AR000DR9K9
744 * @tc.author: yiguang
745 */
746 HWTEST_F(DistributedDBInterfacesIndexUnitTest, CheckSchemaSkipsize003, TestSize.Level1)
747 {
748 PrepareInfoForCheckSchemaSkipsize003();
749 string storeId = "CheckSchemaSkipsize003";
750 KvStoreNbDelegate::Option option = {true, false, false};
751 /**
752 * @tc.steps:step1. Set "SCHEMA_SKIPSIZE" in the schema as 20 to create the schema database.
753 * @tc.expected: step1. return OK.
754 */
755 option.schema = g_schemaString1;
756 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
757 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
758 EXPECT_EQ(g_kvDelegateStatus, OK);
759
760 /**
761 * @tc.steps:step5. Write a value whose prefix is 19 and strictly in accordance with the schema.
762 * @tc.expected: step5. return OK.
763 */
764 Key key001{'1'};
765 Value value001(g_valueString1.begin(), g_valueString1.end());
766 EXPECT_TRUE(g_kvNbDelegatePtr->Put(key001, value001) != OK);
767 /**
768 * @tc.steps:step5. Write a value whose prefix is 20 and strictly in accordance with the schema.
769 * @tc.expected: step5. return OK.
770 */
771 Key key002{'2'};
772 Value value002(g_valueString2.begin(), g_valueString2.end());
773 EXPECT_TRUE(g_kvNbDelegatePtr->Put(key002, value002) == OK);
774 // Clear
775 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
776 EXPECT_EQ(g_mgr.DeleteKvStore("CheckSchemaSkipsize003"), OK);
777 ResetGlobalVariable();
778 }
779
780 /**
781 * @tc.name: schema compare with skipsize 004
782 * @tc.desc: When the SCHEMA_SKIPSIZE definitions of two Schemas are different,
783 * they will be regarded as inconsistent and incompatible
784 * @tc.type: FUNC
785 * @tc.require: AR000DR9K9
786 * @tc.author: yiguang
787 */
788 HWTEST_F(DistributedDBInterfacesIndexUnitTest, SchemaCompareSkipsize004, TestSize.Level1)
789 {
790 PrepareCommonInfo(false);
791 string storeId = "SchemaCompareSkipsize004";
792 KvStoreNbDelegate::Option option = {true, false, false};
793 /**
794 * @tc.steps:step1. Set "SCHEMA_SKIPSIZE" in the schema as 0 to create the schema database.
795 * @tc.expected: step1. return OK.
796 */
797 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(), 0, false, true);
798 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
799 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
800 EXPECT_EQ(g_kvDelegateStatus, OK);
801
802 /**
803 * @tc.steps:step2. Modify the schema, SCHEMA_SKIPSIZE in the new schema is not defined,
804 * open the database repeatedly.
805 * @tc.expected: step2. return OK.
806 */
807 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(), 0, false, false);
808 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback2);
809 ASSERT_TRUE(g_kvNbDelegatePtr2 != nullptr);
810 EXPECT_EQ(g_kvDelegateStatus2, OK);
811
812 /**
813 * @tc.steps:step3. Close the database.
814 * @tc.expected: step3. return OK.
815 */
816 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
817 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr2), OK);
818
819 /**
820 * @tc.steps:step4. SCHEMA_SKIPSIZE in the schema is not defined, reopen the database;
821 * @tc.expected: step4. return OK.
822 */
823 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
824 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
825 EXPECT_EQ(g_kvDelegateStatus, OK);
826
827 /**
828 * @tc.steps:step5. Modify the schema, set SCHEMA_SKIPSIZE to 8 in the new schema,
829 * and open the database repeatedly;
830 * @tc.expected: step5. return OK.
831 */
832 option.schema = GenerateSchemaString(g_pathGroup1, vector<FieldPath>(), 8, false, true); // skipsize 8 in schema
833 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback2);
834 EXPECT_TRUE(g_kvNbDelegatePtr2 == nullptr);
835 EXPECT_TRUE(g_kvDelegateStatus2 != OK);
836
837 /**
838 * @tc.steps:step6. Close the database.
839 * @tc.expected: step6. return OK.
840 */
841 EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK);
842
843 /**
844 * @tc.steps:step4. Modify the schema, set SCHEMA_SKIPSIZE to 8 in the new schema, reopen the database;
845 * @tc.expected: step4. return OK.
846 */
847 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
848 EXPECT_TRUE(g_kvNbDelegatePtr2 == nullptr);
849 EXPECT_TRUE(g_kvDelegateStatus != OK);
850 EXPECT_EQ(g_mgr.DeleteKvStore("SchemaCompareSkipsize004"), OK);
851 ResetGlobalVariable();
852 }
853 #endif