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 // define some variables to init a KvStoreDelegateManager object.
46 KvStoreDelegateManager g_mgr("app0", "user0");
47 std::string g_testDir;
48 KvStoreConfig g_config;
49 std::string g_storeName = "schema_put_test";
50
51 // define the g_kvNbDelegateCallback, used to get some information when open a kv store.
52 DBStatus g_kvDelegateStatus = INVALID_ARGS;
53 KvStoreNbDelegate *g_kvStore = nullptr;
54 CipherPassword g_passwd;
55 KvStoreNbDelegate::Option g_strictOpt = {true, false, false, CipherType::DEFAULT, g_passwd,
56 VALID_SCHEMA_STRICT_DEFINE};
57 KvStoreNbDelegate::Option g_compOpt = {true, false, false, CipherType::DEFAULT, g_passwd,
58 VALID_SCHEMA_COMPA_DEFINE};
59
KvStoreNbDelegateCallback(DBStatus statusSrc,KvStoreNbDelegate * kvStoreSrc,DBStatus * statusDst,KvStoreNbDelegate ** kvStoreDst)60 void KvStoreNbDelegateCallback(
61 DBStatus statusSrc, KvStoreNbDelegate* kvStoreSrc, DBStatus* statusDst, KvStoreNbDelegate** kvStoreDst)
62 {
63 *statusDst = statusSrc;
64 *kvStoreDst = kvStoreSrc;
65 }
66
67 // the type of g_kvNbDelegateCallback is function<void(DBStatus, KvStoreDelegate*)>
68 auto g_kvNbDelegateCallback = std::bind(&KvStoreNbDelegateCallback, std::placeholders::_1,
69 std::placeholders::_2, &g_kvDelegateStatus, &g_kvStore);
70
CheckPutSchemaData(KvStoreNbDelegate * kvStore)71 void CheckPutSchemaData(KvStoreNbDelegate *kvStore)
72 {
73 ASSERT_NE(kvStore, nullptr);
74 Key key;
75 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
76 /**
77 * @tc.steps:step1. Put one data whose value has less fields than the schema(less value is not null).
78 * @tc.expected: step1. return CONSTRAIN_VIOLATION.
79 */
80 std::string lessData = "{\"field_name1\":true}";
81 Value value(lessData.begin(), lessData.end());
82 EXPECT_EQ(g_kvStore->Put(key, value), CONSTRAIN_VIOLATION);
83
84 /**
85 * @tc.steps:step2. Put one data whose value has different type with the schema.
86 * @tc.expected: step2. return INVALID_FIELD_TYPE.
87 */
88 std::string typeDiffData = "{\"field_name1\":30,\"field_name2\":10}";
89 value.assign(typeDiffData.begin(), typeDiffData.end());
90 EXPECT_EQ(kvStore->Put(key, value), INVALID_FIELD_TYPE);
91
92 /**
93 * @tc.steps:step3. Put one data whose value has constrain violation with the schema.
94 * @tc.expected: step3. return CONSTRAIN_VIOLATION.
95 */
96 std::string constrainDiffData = "{\"field_name1\":false,\"field_name2\":null}";
97 value.assign(constrainDiffData.begin(), constrainDiffData.end());
98 EXPECT_EQ(kvStore->Put(key, value), CONSTRAIN_VIOLATION);
99
100 /**
101 * @tc.steps:step4. Put one data whose value has invalid json.
102 * @tc.expected: step4. return INVALID_FORMAT.
103 */
104 std::string invalidJsonData = "{\"field_name1\":false,\"field_name2\":10";
105 value.assign(invalidJsonData.begin(), invalidJsonData.end());
106 EXPECT_EQ(kvStore->Put(key, value), INVALID_FORMAT);
107
108 /**
109 * @tc.steps:step5. Put one data whose value is empty.
110 * @tc.expected: step5. return INVALID_FORMAT.
111 */
112 value.clear();
113 EXPECT_EQ(kvStore->Put(key, value), INVALID_FORMAT);
114
115 /**
116 * @tc.steps:step6. Put one data whose value is match with the schema.
117 * @tc.expected: step6. return INVALID_FORMAT.
118 */
119 std::string validJsonData = "{\"field_name1\":false,\"field_name2\":10}";
120 value.assign(validJsonData.begin(), validJsonData.end());
121 EXPECT_EQ(kvStore->Put(key, value), OK);
122 }
123
CheckPutBatchSchemaData(KvStoreNbDelegate * kvStore)124 void CheckPutBatchSchemaData(KvStoreNbDelegate *kvStore)
125 {
126 ASSERT_NE(kvStore, nullptr);
127 /**
128 * @tc.steps:step1. Put the batch data, one data is invalid.
129 * @tc.expected: step1. return INVALID_FORMAT.
130 */
131 Key key;
132 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
133 std::string invalidData = "{\"field_name1\":true, \"field_name2\":null}";
134 Value value(invalidData.begin(), invalidData.end());
135 std::vector<Entry> entries;
136 entries.push_back({key, value});
137
138 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
139 std::string validData = "{\"field_name1\":true, \"field_name2\":0}";
140 value.assign(validData.begin(), validData.end());
141 entries.push_back({key, value});
142
143 EXPECT_NE(kvStore->PutBatch(entries), INVALID_FORMAT);
144
145 entries.clear();
146 entries.push_back({key, value});
147
148 /**
149 * @tc.steps:step2. Put the batch data, both valid.
150 * @tc.expected: step2. return OK.
151 */
152 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
153 validData = "{\"field_name1\":null, \"field_name2\":30}";
154 value.assign(validData.begin(), validData.end());
155 entries.push_back({key, value});
156
157 EXPECT_EQ(kvStore->PutBatch(entries), OK);
158 }
159 }
160 class DistributedDBInterfacesNBDelegateSchemaPutTest : public testing::Test {
161 public:
162 static void SetUpTestCase(void);
163 static void TearDownTestCase(void);
164 void SetUp();
165 void TearDown();
166 };
167
SetUpTestCase(void)168 void DistributedDBInterfacesNBDelegateSchemaPutTest::SetUpTestCase(void)
169 {
170 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
171 g_config.dataDir = g_testDir;
172 g_mgr.SetKvStoreConfig(g_config);
173 }
174
TearDownTestCase(void)175 void DistributedDBInterfacesNBDelegateSchemaPutTest::TearDownTestCase(void)
176 {
177 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
178 LOGE("rm test db files error!");
179 }
180 }
181
SetUp(void)182 void DistributedDBInterfacesNBDelegateSchemaPutTest::SetUp(void)
183 {
184 DistributedDBToolsUnitTest::PrintTestCaseInfo();
185 }
186
TearDown(void)187 void DistributedDBInterfacesNBDelegateSchemaPutTest::TearDown(void)
188 {
189 EXPECT_EQ(g_mgr.CloseKvStore(g_kvStore), OK);
190 EXPECT_EQ(g_mgr.DeleteKvStore(g_storeName), OK);
191 g_kvStore = nullptr;
192 g_kvDelegateStatus = INVALID_ARGS;
193 }
194
195 /**
196 * @tc.name: PutValueStrictSchemaCheck001
197 * @tc.desc: Check the value in the strict schema mode.
198 * @tc.type: FUNC
199 * @tc.require: AR000DR9K5
200 * @tc.author: wangbingquan
201 */
202 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueStrictSchemaCheck001, TestSize.Level1)
203 {
204 g_mgr.GetKvStore(g_storeName, g_strictOpt, g_kvNbDelegateCallback);
205 ASSERT_TRUE(g_kvStore != nullptr);
206 EXPECT_TRUE(g_kvDelegateStatus == OK);
207
208 /**
209 * @tc.steps:step1. Put one data whose value has more fields than the schema.
210 * @tc.expected: step1. return INVALID_VALUE_FIELDS.
211 */
212 Key key;
213 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
214 std::string moreData = "{\"field_name1\":true,\"field_name2\":10,\"field_name3\":10}";
215 Value value(moreData.begin(), moreData.end());
216 EXPECT_EQ(g_kvStore->Put(key, value), INVALID_VALUE_FIELDS);
217
218 /**
219 * @tc.steps:step2. Put one data whose value has diff fields than the schema.
220 * @tc.expected: step2. return INVALID_VALUE_FIELDS.
221 */
222 std::string diffData = "{\"field_name2\":10,\"field_name3\":10}";
223 Value value1(diffData.begin(), diffData.end());
224 EXPECT_EQ(g_kvStore->Put(key, value1), INVALID_VALUE_FIELDS);
225
226 std::string filedDiffData = "{\"field_name1\":true,\"field_name3\":10}";
227 value.assign(filedDiffData.begin(), filedDiffData.end());
228 EXPECT_EQ(g_kvStore->Put(key, value), INVALID_VALUE_FIELDS);
229
230 /**
231 * @tc.steps:step3. Put the data whose value is mismatch with the schema.
232 * @tc.expected: step3. return not OK.
233 */
234 CheckPutSchemaData(g_kvStore);
235 CheckPutBatchSchemaData(g_kvStore);
236 }
237
238 /**
239 * @tc.name: PutValueReadOnlyCheck001
240 * @tc.desc: Test writing the data into the no-schema kvStore which has schema originally.
241 * @tc.type: FUNC
242 * @tc.require: AR000DR9K5
243 * @tc.author: wangbingquan
244 */
245 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueCompaSchemaCheck001, TestSize.Level1)
246 {
247 g_mgr.GetKvStore(g_storeName, g_compOpt, g_kvNbDelegateCallback);
248 ASSERT_TRUE(g_kvStore != nullptr);
249 EXPECT_TRUE(g_kvDelegateStatus == OK);
250 /**
251 * @tc.steps:step1. Put one data whose value has more fields than the schema.
252 * @tc.expected: step1. return OK.
253 */
254 Key key;
255 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
256 std::string moreData = "{\"field_name1\":true,\"field_name2\":10,\"field_name3\":10}";
257 Value value(moreData.begin(), moreData.end());
258 EXPECT_EQ(g_kvStore->Put(key, value), OK);
259
260
261 /**
262 * @tc.steps:step2. Put one data whose value has different fields with the schema(less value is not null).
263 * @tc.expected: step2. return CONSTRAIN_VIOLATION.
264 */
265 std::string filedDiffData = "{\"field_name1\":true,\"field_name3\":10}";
266 value.assign(filedDiffData.begin(), filedDiffData.end());
267 EXPECT_EQ(g_kvStore->Put(key, value), CONSTRAIN_VIOLATION);
268
269 /**
270 * @tc.steps:step2. Put the data whose value is mismatch with the schema.
271 * @tc.expected: step2. return not OK.
272 */
273 CheckPutSchemaData(g_kvStore);
274 CheckPutBatchSchemaData(g_kvStore);
275 }
276
277 /**
278 * @tc.name: PutValueReadOnlyCheck001
279 * @tc.desc: Test writing the data into the no-schema kvStore which has schema originally.
280 * @tc.type: FUNC
281 * @tc.require: AR000DR9K5
282 * @tc.author: wangbingquan
283 */
284 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, PutValueReadOnlyCheck001, TestSize.Level1)
285 {
286 /**
287 * @tc.steps:step1. Open the kv store with valid schema, and close it.
288 */
289 g_mgr.GetKvStore(g_storeName, g_compOpt, g_kvNbDelegateCallback);
290 ASSERT_TRUE(g_kvStore != nullptr);
291 EXPECT_TRUE(g_kvDelegateStatus == OK);
292 EXPECT_EQ(g_mgr.CloseKvStore(g_kvStore), OK);
293 /**
294 * @tc.steps:step2. Open the kv store with no schema.
295 * @tc.expected: step2. return OK.
296 */
297 DistributedDB::KvStoreNbDelegate::Option option = g_compOpt;
298 option.schema.clear();
299 g_mgr.GetKvStore(g_storeName, option, g_kvNbDelegateCallback);
300 ASSERT_TRUE(g_kvStore != nullptr);
301 EXPECT_TRUE(g_kvDelegateStatus == OK);
302 /**
303 * @tc.steps:step3. Put the data.
304 * @tc.expected: step3. return READ_ONLY.
305 */
306 Key key;
307 DistributedDBToolsUnitTest::GetRandomKeyValue(key);
308 std::string valueData = "{\"field_name1\":true,\"field_name2\":20}";
309 Value value(valueData.begin(), valueData.end());
310 EXPECT_EQ(g_kvStore->Put(key, value), READ_ONLY);
311 }
312
313 /**
314 * @tc.name: QueryDeleted001
315 * @tc.desc: Test the query in the deleted scene.
316 * @tc.type: FUNC
317 * @tc.require: AR000DR9K5
318 * @tc.author: wangbingquan
319 */
320 HWTEST_F(DistributedDBInterfacesNBDelegateSchemaPutTest, QueryDeleted001, TestSize.Level1)
321 {
322 g_mgr.GetKvStore(g_storeName, g_strictOpt, g_kvNbDelegateCallback);
323 ASSERT_TRUE(g_kvStore != nullptr);
324 EXPECT_TRUE(g_kvDelegateStatus == OK);
325
326 /**
327 * @tc.steps:step1. Put 2 schema data.
328 * @tc.expected: step1. return OK.
329 */
330 Key key1;
331 std::string valueData = "{\"field_name1\":true,\"field_name2\":1}";
332 Value value(valueData.begin(), valueData.end());
333 DistributedDBToolsUnitTest::GetRandomKeyValue(key1);
334 EXPECT_EQ(g_kvStore->Put(key1, value), OK);
335
336 Key key2;
337 valueData = "{\"field_name1\":true,\"field_name2\":2}";
338 value.assign(valueData.begin(), valueData.end());
339 DistributedDBToolsUnitTest::GetRandomKeyValue(key2);
340 EXPECT_EQ(g_kvStore->Put(key2, value), OK);
341
342 /**
343 * @tc.steps:step2. Get the data through the query condition where the field value is 1.
344 * @tc.expected: step2. GetEntries return OK, and the data num is 1.
345 */
346 std::vector<Entry> entries;
347 KvStoreResultSet *resultSet = nullptr;
348 Query query = Query::Select().EqualTo("$.field_name2", 1);
349 EXPECT_EQ(g_kvStore->GetEntries(query, entries), OK);
350 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OK);
351 ASSERT_NE(resultSet, nullptr);
352 EXPECT_EQ(resultSet->GetCount(), 1);
353 int count = 0;
354 EXPECT_EQ(g_kvStore->GetCount(query, count), OK);
355 EXPECT_EQ(count, 1);
356 EXPECT_EQ(g_kvStore->CloseResultSet(resultSet), OK);
357
358 /**
359 * @tc.steps:step3. Delete the data whose field value is 1.
360 */
361 EXPECT_EQ(g_kvStore->Delete(key1), OK);
362
363 /**
364 * @tc.steps:step4. Get the data whose field value is 1.
365 * @tc.expected: step4. GetEntries return NOT_FOUND, and the data num is 0.
366 */
367 EXPECT_EQ(g_kvStore->GetEntries(query, entries), NOT_FOUND);
368 EXPECT_EQ(g_kvStore->GetCount(query, count), NOT_FOUND);
369 EXPECT_EQ(g_kvStore->GetEntries(query, resultSet), OK);
370 ASSERT_NE(resultSet, nullptr);
371 EXPECT_EQ(resultSet->GetCount(), 0);
372 EXPECT_EQ(g_kvStore->CloseResultSet(resultSet), OK);
373 }
374 #endif