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 <functional>
18 #include <gtest/gtest.h>
19 #include <string>
20
21 #include "distributeddb_tools_unit_test.h"
22 #include "kv_store_delegate_manager.h"
23 #include "kv_store_nb_delegate.h"
24 #include "query.h"
25
26 using namespace testing::ext;
27 using namespace DistributedDB;
28 using namespace DistributedDBUnitTest;
29
30 namespace {
31 const std::string VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\","
32 "\"SCHEMA_MODE\":\"STRICT\","
33 "\"SCHEMA_DEFINE\":{"
34 "\"field_name1\":\"BOOL\","
35 "\"field_name2\":\"INTEGER, NOT NULL\""
36 "},"
37 "\"SCHEMA_INDEXES\":[\"$.field_name1\"]}";
38 const std::string VALID_SCHEMA_COMPA_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\","
39 "\"SCHEMA_MODE\":\"COMPATIBLE\","
40 "\"SCHEMA_DEFINE\":{"
41 "\"field_name1\":\"BOOL\","
42 "\"field_name2\":\"INTEGER, NOT NULL\""
43 "},"
44 "\"SCHEMA_INDEXES\":[\"$.field_name1\"]}";
45 const std::string VALID_SCHEMA_COMPA_WITH_SQL_KEYWORD_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\","
46 "\"SCHEMA_MODE\":\"COMPATIBLE\","
47 "\"SCHEMA_DEFINE\":{"
48 "\"create\":\"BOOL\","
49 "\"default\":\"INTEGER, NOT NULL\""
50 "},"
51 "\"SCHEMA_INDEXES\":[\"create\"]}";
52 // define some variables to init a KvStoreDelegateManager object.
53 KvStoreDelegateManager g_mgr("app0", "user0");
54 std::string g_testDir;
55 KvStoreConfig g_config;
56 std::string g_storeName = "schema_put_test";
57
58 // define the g_kvNbDelegateCallback, used to get some information when open a kv store.
59 DBStatus g_kvDelegateStatus = INVALID_ARGS;
60 KvStoreNbDelegate *g_kvStore = nullptr;
61 CipherPassword g_passwd;
62 KvStoreNbDelegate::Option g_strictOpt = {true, false, false, CipherType::DEFAULT, g_passwd,
63 VALID_SCHEMA_STRICT_DEFINE};
64 KvStoreNbDelegate::Option g_compOpt = {true, false, false, CipherType::DEFAULT, g_passwd,
65 VALID_SCHEMA_COMPA_DEFINE};
66
KvStoreNbDelegateCallback(DBStatus statusSrc,KvStoreNbDelegate * kvStoreSrc,DBStatus * statusDst,KvStoreNbDelegate ** kvStoreDst)67 void KvStoreNbDelegateCallback(
68 DBStatus statusSrc, KvStoreNbDelegate* kvStoreSrc, DBStatus* statusDst, KvStoreNbDelegate** kvStoreDst)
69 {
70 *statusDst = statusSrc;
71 *kvStoreDst = kvStoreSrc;
72 }
73
74 // the type of g_kvNbDelegateCallback is function<void(DBStatus, KvStoreDelegate*)>
75 auto g_kvNbDelegateCallback = std::bind(&KvStoreNbDelegateCallback, std::placeholders::_1,
76 std::placeholders::_2, &g_kvDelegateStatus, &g_kvStore);
77
CheckPutSchemaData(KvStoreNbDelegate * kvStore)78 void CheckPutSchemaData(KvStoreNbDelegate *kvStore)
79 {
80 ASSERT_NE(kvStore, nullptr);
81 Key key;
82 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
83 /**
84 * @tc.steps:step1. Put one data whose value has less fields than the schema(less value is not null).
85 * @tc.expected: step1. return CONSTRAIN_VIOLATION.
86 */
87 std::string lessData = "{\"field_name1\":true}";
88 Value value(lessData.begin(), lessData.end());
89 EXPECT_EQ(g_kvStore->Put(key, value), CONSTRAIN_VIOLATION);
90
91 /**
92 * @tc.steps:step2. Put one data whose value has different type with the schema.
93 * @tc.expected: step2. return INVALID_FIELD_TYPE.
94 */
95 std::string typeDiffData = "{\"field_name1\":30,\"field_name2\":10}";
96 value.assign(typeDiffData.begin(), typeDiffData.end());
97 EXPECT_EQ(kvStore->Put(key, value), INVALID_FIELD_TYPE);
98
99 /**
100 * @tc.steps:step3. Put one data whose value has constrain violation with the schema.
101 * @tc.expected: step3. return CONSTRAIN_VIOLATION.
102 */
103 std::string constrainDiffData = "{\"field_name1\":false,\"field_name2\":null}";
104 value.assign(constrainDiffData.begin(), constrainDiffData.end());
105 EXPECT_EQ(kvStore->Put(key, value), CONSTRAIN_VIOLATION);
106
107 /**
108 * @tc.steps:step4. Put one data whose value has invalid json.
109 * @tc.expected: step4. return INVALID_FORMAT.
110 */
111 std::string invalidJsonData = "{\"field_name1\":false,\"field_name2\":10";
112 value.assign(invalidJsonData.begin(), invalidJsonData.end());
113 EXPECT_EQ(kvStore->Put(key, value), INVALID_FORMAT);
114
115 /**
116 * @tc.steps:step5. Put one data whose value is empty.
117 * @tc.expected: step5. return INVALID_FORMAT.
118 */
119 value.clear();
120 EXPECT_EQ(kvStore->Put(key, value), INVALID_FORMAT);
121
122 /**
123 * @tc.steps:step6. Put one data whose value is match with the schema.
124 * @tc.expected: step6. return INVALID_FORMAT.
125 */
126 std::string validJsonData = "{\"field_name1\":false,\"field_name2\":10}";
127 value.assign(validJsonData.begin(), validJsonData.end());
128 EXPECT_EQ(kvStore->Put(key, value), OK);
129 }
130
CheckPutBatchSchemaData(KvStoreNbDelegate * kvStore)131 void CheckPutBatchSchemaData(KvStoreNbDelegate *kvStore)
132 {
133 ASSERT_NE(kvStore, nullptr);
134 /**
135 * @tc.steps:step1. Put the batch data, one data is invalid.
136 * @tc.expected: step1. return INVALID_FORMAT.
137 */
138 Key key;
139 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
140 std::string invalidData = "{\"field_name1\":true, \"field_name2\":null}";
141 Value value(invalidData.begin(), invalidData.end());
142 std::vector<Entry> entries;
143 entries.push_back({key, value});
144
145 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
146 std::string validData = "{\"field_name1\":true, \"field_name2\":0}";
147 value.assign(validData.begin(), validData.end());
148 entries.push_back({key, value});
149
150 EXPECT_NE(kvStore->PutBatch(entries), INVALID_FORMAT);
151
152 entries.clear();
153 entries.push_back({key, value});
154
155 /**
156 * @tc.steps:step2. Put the batch data, both valid.
157 * @tc.expected: step2. return OK.
158 */
159 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
160 validData = "{\"field_name1\":null, \"field_name2\":30}";
161 value.assign(validData.begin(), validData.end());
162 entries.push_back({key, value});
163
164 EXPECT_EQ(kvStore->PutBatch(entries), OK);
165 }
166 }
167 class DistributedDBInterfacesNBDelegateSchemaPutTest : public testing::Test {
168 public:
169 static void SetUpTestCase(void);
170 static void TearDownTestCase(void);
171 void SetUp();
172 void TearDown();
173 };
174
SetUpTestCase(void)175 void DistributedDBInterfacesNBDelegateSchemaPutTest::SetUpTestCase(void)
176 {
177 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
178 g_config.dataDir = g_testDir;
179 g_mgr.SetKvStoreConfig(g_config);
180 }
181
TearDownTestCase(void)182 void DistributedDBInterfacesNBDelegateSchemaPutTest::TearDownTestCase(void)
183 {
184 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
185 LOGE("rm test db files error!");
186 }
187 }
188
SetUp(void)189 void DistributedDBInterfacesNBDelegateSchemaPutTest::SetUp(void)
190 {
191 DistributedDBToolsUnitTest::PrintTestCaseInfo();
192 }
193
TearDown(void)194 void DistributedDBInterfacesNBDelegateSchemaPutTest::TearDown(void)
195 {
196 EXPECT_EQ(g_mgr.CloseKvStore(g_kvStore), OK);
197 EXPECT_EQ(g_mgr.DeleteKvStore(g_storeName), OK);
198 g_kvStore = nullptr;
199 g_kvDelegateStatus = INVALID_ARGS;
200 }
201
202 /**
203 * @tc.name: PutValueStrictSchemaCheck001
204 * @tc.desc: Check the value in the strict schema mode.
205 * @tc.type: FUNC
206 * @tc.require:
207 * @tc.author: wangbingquan
208 */
209 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueStrictSchemaCheck001, TestSize.Level1)
210 {
211 g_mgr.GetKvStore(g_storeName, g_strictOpt, g_kvNbDelegateCallback);
212 ASSERT_TRUE(g_kvStore != nullptr);
213 EXPECT_TRUE(g_kvDelegateStatus == OK);
214
215 /**
216 * @tc.steps:step1. Put one data whose value has more fields than the schema.
217 * @tc.expected: step1. return INVALID_VALUE_FIELDS.
218 */
219 Key key;
220 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
221 std::string moreData = "{\"field_name1\":true,\"field_name2\":10,\"field_name3\":10}";
222 Value value(moreData.begin(), moreData.end());
223 EXPECT_EQ(g_kvStore->Put(key, value), INVALID_VALUE_FIELDS);
224
225 /**
226 * @tc.steps:step2. Put one data whose value has diff fields than the schema.
227 * @tc.expected: step2. return INVALID_VALUE_FIELDS.
228 */
229 std::string diffData = "{\"field_name2\":10,\"field_name3\":10}";
230 Value value1(diffData.begin(), diffData.end());
231 EXPECT_EQ(g_kvStore->Put(key, value1), INVALID_VALUE_FIELDS);
232
233 std::string filedDiffData = "{\"field_name1\":true,\"field_name3\":10}";
234 value.assign(filedDiffData.begin(), filedDiffData.end());
235 EXPECT_EQ(g_kvStore->Put(key, value), INVALID_VALUE_FIELDS);
236
237 /**
238 * @tc.steps:step3. Put the data whose value is mismatch with the schema.
239 * @tc.expected: step3. return not OK.
240 */
241 CheckPutSchemaData(g_kvStore);
242 CheckPutBatchSchemaData(g_kvStore);
243 }
244
245 /**
246 * @tc.name: PutValueReadOnlyCheck001
247 * @tc.desc: Test writing the data into the no-schema kvStore which has schema originally.
248 * @tc.type: FUNC
249 * @tc.require:
250 * @tc.author: wangbingquan
251 */
252 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueCompaSchemaCheck001, TestSize.Level1)
253 {
254 g_mgr.GetKvStore(g_storeName, g_compOpt, g_kvNbDelegateCallback);
255 ASSERT_TRUE(g_kvStore != nullptr);
256 EXPECT_TRUE(g_kvDelegateStatus == OK);
257 /**
258 * @tc.steps:step1. Put one data whose value has more fields than the schema.
259 * @tc.expected: step1. return OK.
260 */
261 Key key;
262 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
263 std::string moreData = "{\"field_name1\":true,\"field_name2\":10,\"field_name3\":10}";
264 Value value(moreData.begin(), moreData.end());
265 EXPECT_EQ(g_kvStore->Put(key, value), OK);
266
267
268 /**
269 * @tc.steps:step2. Put one data whose value has different fields with the schema(less value is not null).
270 * @tc.expected: step2. return CONSTRAIN_VIOLATION.
271 */
272 std::string filedDiffData = "{\"field_name1\":true,\"field_name3\":10}";
273 value.assign(filedDiffData.begin(), filedDiffData.end());
274 EXPECT_EQ(g_kvStore->Put(key, value), CONSTRAIN_VIOLATION);
275
276 /**
277 * @tc.steps:step2. Put the data whose value is mismatch with the schema.
278 * @tc.expected: step2. return not OK.
279 */
280 CheckPutSchemaData(g_kvStore);
281 CheckPutBatchSchemaData(g_kvStore);
282 }
283
284 /**
285 * @tc.name: PutValueReadOnlyCheck001
286 * @tc.desc: Test writing the data into the no-schema kvStore which has schema originally.
287 * @tc.type: FUNC
288 * @tc.require:
289 * @tc.author: wangbingquan
290 */
291 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueReadOnlyCheck001, TestSize.Level1)
292 {
293 /**
294 * @tc.steps:step1. Open the kv store with valid schema, and close it.
295 */
296 g_mgr.GetKvStore(g_storeName, g_compOpt, g_kvNbDelegateCallback);
297 ASSERT_TRUE(g_kvStore != nullptr);
298 EXPECT_TRUE(g_kvDelegateStatus == OK);
299 EXPECT_EQ(g_mgr.CloseKvStore(g_kvStore), OK);
300 /**
301 * @tc.steps:step2. Open the kv store with no schema.
302 * @tc.expected: step2. return OK.
303 */
304 DistributedDB::KvStoreNbDelegate::Option option = g_compOpt;
305 option.schema.clear();
306 g_mgr.GetKvStore(g_storeName, option, g_kvNbDelegateCallback);
307 ASSERT_TRUE(g_kvStore != nullptr);
308 EXPECT_TRUE(g_kvDelegateStatus == OK);
309 /**
310 * @tc.steps:step3. Put the data.
311 * @tc.expected: step3. return READ_ONLY.
312 */
313 Key key;
314 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
315 std::string valueData = "{\"field_name1\":true,\"field_name2\":20}";
316 Value value(valueData.begin(), valueData.end());
317 EXPECT_EQ(g_kvStore->Put(key, value), READ_ONLY);
318 }
319
320 /**
321 * @tc.name: QueryDeleted001
322 * @tc.desc: Test the query in the deleted scene.
323 * @tc.type: FUNC
324 * @tc.require:
325 * @tc.author: wangbingquan
326 */
327 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, QueryDeleted001, TestSize.Level1)
328 {
329 g_mgr.GetKvStore(g_storeName, g_strictOpt, g_kvNbDelegateCallback);
330 ASSERT_TRUE(g_kvStore != nullptr);
331 EXPECT_TRUE(g_kvDelegateStatus == OK);
332
333 /**
334 * @tc.steps:step1. Put 2 schema data.
335 * @tc.expected: step1. return OK.
336 */
337 Key key1;
338 std::string valueData = "{\"field_name1\":true,\"field_name2\":1}";
339 Value value(valueData.begin(), valueData.end());
340 DistributedDBToolsUnitTest::GetRandomKeyValue(key1);
341 EXPECT_EQ(g_kvStore->Put(key1, value), OK);
342
343 Key key2;
344 valueData = "{\"field_name1\":true,\"field_name2\":2}";
345 value.assign(valueData.begin(), valueData.end());
346 DistributedDBToolsUnitTest::GetRandomKeyValue(key2);
347 EXPECT_EQ(g_kvStore->Put(key2, value), OK);
348
349 /**
350 * @tc.steps:step2. Get the data through the query condition where the field value is 1.
351 * @tc.expected: step2. GetEntries return OK, and the data num is 1.
352 */
353 std::vector<Entry> entries;
354 KvStoreResultSet *resultSet = nullptr;
355 Query query = Query::Select().EqualTo("$.field_name2", 1);
356 EXPECT_EQ(g_kvStore->GetEntries(query, entries), OK);
357 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OK);
358 ASSERT_NE(resultSet, nullptr);
359 EXPECT_EQ(resultSet->GetCount(), 1);
360 int count = 0;
361 EXPECT_EQ(g_kvStore->GetCount(query, count), OK);
362 EXPECT_EQ(count, 1);
363 EXPECT_EQ(g_kvStore->CloseResultSet(resultSet), OK);
364
365 /**
366 * @tc.steps:step3. Delete the data whose field value is 1.
367 */
368 EXPECT_EQ(g_kvStore->Delete(key1), OK);
369
370 /**
371 * @tc.steps:step4. Get the data whose field value is 1.
372 * @tc.expected: step4. GetEntries return NOT_FOUND, and the data num is 0.
373 */
374 EXPECT_EQ(g_kvStore->GetEntries(query, entries), NOT_FOUND);
375 EXPECT_EQ(g_kvStore->GetCount(query, count), NOT_FOUND);
376 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OK);
377 ASSERT_NE(resultSet, nullptr);
378 EXPECT_EQ(resultSet->GetCount(), 0);
379 EXPECT_EQ(g_kvStore->CloseResultSet(resultSet), OK);
380 }
381
382 /**
383 * @tc.name: SqliteKeyWord001
384 * @tc.desc: Test kv schema with sqlite key world.
385 * @tc.type: FUNC
386 * @tc.require:
387 * @tc.author: lianhuix
388 */
389 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, SqliteKeyWord001, TestSize.Level1)
390 {
391 KvStoreNbDelegate::Option option = {true, false, false};
392 option.schema = VALID_SCHEMA_COMPA_WITH_SQL_KEYWORD_DEFINE;
393 g_mgr.GetKvStore(g_storeName, option, g_kvNbDelegateCallback);
394 ASSERT_TRUE(g_kvStore != nullptr);
395 EXPECT_TRUE(g_kvDelegateStatus == OK);
396
397 /**
398 * @tc.steps:step1. Put one data whose value has more fields than the schema.
399 * @tc.expected: step1. return INVALID_VALUE_FIELDS.
400 */
401 Key key;
402 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
403 std::string moreData = "{\"create\":true,\"default\":10,\"field_name3\":10}";
404 Value value(moreData.begin(), moreData.end());
405 EXPECT_EQ(g_kvStore->Put(key, value), OK);
406
407 std::vector<Entry> entries;
408 Query query = Query::Select().EqualTo("create", true);
409 EXPECT_EQ(g_kvStore->GetEntries(query, entries), OK);
410 EXPECT_EQ(entries.size(), 1U);
411 }
412
413 /**
414 * @tc.name: ResultSetLimitTest001
415 * @tc.desc: Get result set over limit
416 * @tc.type: FUNC
417 * @tc.require:
418 * @tc.author: lianhuix
419 */
420 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, ResultSetLimitTest001, TestSize.Level0)
421 {
422 /**
423 * @tc.steps:step1. Create database.
424 * @tc.expected: step1. Returns a non-null kvstore.
425 */
426 g_mgr.GetKvStore(g_storeName, g_strictOpt, g_kvNbDelegateCallback);
427 ASSERT_TRUE(g_kvStore != nullptr);
428 EXPECT_TRUE(g_kvDelegateStatus == OK);
429
430 /**
431 * @tc.steps:step2. Put the random entry into the database.
432 * @tc.expected: step2. Returns OK.
433 */
434 Key key1;
435 std::string valueData = "{\"field_name1\":true,\"field_name2\":1}";
436 Value value(valueData.begin(), valueData.end());
437 DistributedDBToolsUnitTest::GetRandomKeyValue(key1);
438 EXPECT_EQ(g_kvStore->Put(key1, value), OK);
439
440 /**
441 * @tc.steps:step3. Get the resultset overlimit.
442 * @tc.expected: step3. In limit returns OK, else return OVER_MAX_LIMITS.
443 */
444 Query query = Query::Select().EqualTo("$.field_name2", 1);
445 std::vector<KvStoreResultSet *> dataResultSet;
446 for (int i = 0; i < 8; i++) { // 8: max result set count
447 KvStoreResultSet *resultSet = nullptr;
448 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OK);
449 dataResultSet.push_back(resultSet);
450 EXPECT_NE(resultSet, nullptr);
451 }
452
453 KvStoreResultSet *resultSet = nullptr;
454 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OVER_MAX_LIMITS);
455 EXPECT_EQ(resultSet, nullptr);
456 if (resultSet != nullptr) {
457 EXPECT_EQ(g_kvStore->CloseResultSet(resultSet), OK);
458 }
459
460 /**
461 * @tc.steps:step4. Close result set.
462 * @tc.expected: step4. Returns OK.
463 */
464 for (auto it : dataResultSet) {
465 EXPECT_EQ(g_kvStore->CloseResultSet(it), OK);
466 }
467 }
468 #endif // OMIT_JSON