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