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 #include "distributeddb_schema_test_tools.h"
16 #include <fstream>
17 #include "distributeddb_nb_test_tools.h"
18
19 using namespace std;
20 using namespace DistributedDB;
21 using namespace DistributedDBDataGenerator;
22
GenerateFixedLenJsonSchemaRecord(const unsigned long serialNo,const EntrySize & entrySize,const uint8_t keyFilledChr,const uint8_t valueFilledChr)23 Entry DistributedDBSchemaTestTools::GenerateFixedLenJsonSchemaRecord(const unsigned long serialNo,
24 const EntrySize &entrySize, const uint8_t keyFilledChr, const uint8_t valueFilledChr)
25 {
26 Entry entry;
27 std::string serialNoStr = std::to_string(serialNo);
28 entry.key.assign(entrySize.keySize - serialNoStr.length(), keyFilledChr);
29 for (unsigned long index = 0; index < serialNoStr.size(); ++index) {
30 entry.key.push_back(serialNoStr[index]);
31 }
32
33 string val = string("{") + "\"field" + std::to_string(FIRST_FIELD) + "\":" + std::to_string(serialNo) + ",";
34 for (unsigned int fieldIndex = SECOND_FIELD; fieldIndex <= THIRTIETH_FIELD; fieldIndex++) {
35 if (fieldIndex == SIXTH_FIELD) {
36 val += "\"field" + std::to_string(fieldIndex) + "\":" + to_string(static_cast<double>(serialNo)) + ",";
37 } else {
38 val += "\"field" + std::to_string(fieldIndex) + "\":" +
39 "\"SchemaPerfTest" + std::to_string(fieldIndex) + "_" + std::to_string(serialNo) + "\",";
40 }
41 }
42 val.back() = '}';
43 size_t found = val.rfind("PerfTest");
44 if (found != string::npos) {
45 string insert = "PerfTest";
46 insert += string(entrySize.valSize - val.length() - 1, valueFilledChr); // consider skipsize 1 byte 'a' below
47 val.replace(found, strlen("PerfTest"), insert);
48 }
49 string scmVal = "a" + val;
50 Value schemaVal(scmVal.begin(), scmVal.end());
51 entry.value = schemaVal;
52 return entry;
53 }
54
GenerateFixedJsonSchemaRecords(const int recordNum,const EntrySize & entrySize,const uint8_t keyFilledChr,const uint8_t valueFilledChr,vector<Key> & allKeys)55 vector<Entry> DistributedDBSchemaTestTools::GenerateFixedJsonSchemaRecords(const int recordNum,
56 const EntrySize &entrySize, const uint8_t keyFilledChr, const uint8_t valueFilledChr, vector<Key> &allKeys)
57 {
58 vector<Entry> entries;
59 for (int serialNo = TEST_START_CNT; serialNo <= recordNum; ++serialNo) {
60 Entry entry = GenerateFixedLenJsonSchemaRecord(serialNo, entrySize, keyFilledChr, valueFilledChr);
61 allKeys.push_back(entry.key);
62 entries.push_back(entry);
63 }
64 return entries;
65 }
66
GenerateFixedLenSchemaPerfRecord(const uint64_t presetRecordsCnt,const uint64_t serialNo,const RecordInfo & recordInfo,const string & valueSkipString)67 Entry DistributedDBSchemaTestTools::GenerateFixedLenSchemaPerfRecord(
68 const uint64_t presetRecordsCnt, const uint64_t serialNo, const RecordInfo &recordInfo,
69 const string &valueSkipString)
70 {
71 Entry entry;
72 std::string serialNoStr = std::to_string(serialNo);
73 entry.key.assign(recordInfo.keyLength - serialNoStr.length(), recordInfo.keyFilledChr);
74 for (unsigned long index = 0; index < serialNoStr.size(); ++index) {
75 entry.key.push_back(serialNoStr[index]);
76 }
77
78 string val = string("{") + "\"field" + std::to_string(FIRST_FIELD) + "\":" + std::to_string(serialNo) + ",";
79 unsigned int fieldIndex;
80 for (fieldIndex = SECOND_FIELD; fieldIndex <= THIRD_FIELD; fieldIndex++) {
81 val += "\"field" + std::to_string(fieldIndex) + "\":" +
82 "\"SchemaPerfTest" + std::to_string(fieldIndex) + "_" + serialNoStr + "\",";
83 }
84 if (serialNo <= static_cast<uint64_t>(presetRecordsCnt) / 2) { // 2 is an half of records.
85 for (fieldIndex = FOURTH_FIELD; fieldIndex <= FIFTH_FIELD; fieldIndex++) {
86 val += "\"field" + std::to_string(fieldIndex) + "\":" +
87 "\"SchemaPerfTest" + std::to_string(fieldIndex) + "_" + serialNoStr + "\",";
88 }
89 }
90 for (; fieldIndex <= THIRTIETH_FIELD; fieldIndex++) {
91 if (fieldIndex == SIXTH_FIELD) {
92 val += "\"field" + std::to_string(fieldIndex) + "\":" + to_string(static_cast<double>(serialNo)) + ",";
93 } else {
94 val += "\"field" + std::to_string(fieldIndex) + "\":" +
95 "\"SchemaPerfTest" + std::to_string(fieldIndex) + "\",";
96 }
97 }
98 val.back() = '}';
99 size_t found = val.rfind("PerfTest");
100 if (found != string::npos) {
101 string insert = "PerfTest";
102 if (recordInfo.valueLength > val.length()) {
103 insert += string(recordInfo.valueLength - val.length(), recordInfo.valueFilledChr);
104 val.replace(found, strlen("PerfTest"), insert);
105 } else {
106 MST_LOG("[GenerateFixedLenSchemaPerfRecord] recordInfo.valueLength(%u) is too short, " \
107 "it should be more than %zu.", recordInfo.valueLength, val.length());
108 return entry;
109 }
110 }
111 string scmVal = valueSkipString + val;
112 Value schemaVal(scmVal.begin(), scmVal.end());
113 entry.value = schemaVal;
114 return entry;
115 }
116
SchemaIndexQuery(const DBParameters & parameters,const string & dbPath,const string & schemaIndex,const Option & option)117 bool DistributedDBSchemaTestTools::SchemaIndexQuery(const DBParameters ¶meters,
118 const string &dbPath, const string &schemaIndex, const Option &option)
119 {
120 int count = 0;
121 string identifier = parameters.userId + "-" + parameters.appId + "-" + parameters.storeId;
122 string hashIdentifierRes = TransferStringToHashHexString(identifier);
123 const string dbName = dbPath + hashIdentifierRes + DATABASE_INFOR_FILE;
124 EncrypteAttribute attribute = {option.isEncryptedDb, option.passwd};
125
126 const string SCHEMA_INDEX_QUERY_SQL = "select count(*) from sqlite_master where name= \'" +
127 schemaIndex + "\' and type = \'index\'";
128
129 DistributedTestTools::QuerySpecifiedData(dbName, SCHEMA_INDEX_QUERY_SQL, attribute, count);
130 return (count == 1);
131 }
132
GenerateCombinationSchemaValue(const vector<vector<string>> & fieldValue)133 vector<string> DistributedDBSchemaTestTools::GenerateCombinationSchemaValue(const vector<vector<string>> &fieldValue)
134 {
135 vector<string> schemasValue;
136 int valueNum = fieldValue.size();
137 for (int index = 0; index < valueNum; index++) {
138 string valueStr;
139 string field1Val = fieldValue[index][INDEX_ZEROTH];
140 if (field1Val != "null") {
141 valueStr = valueStr + "{\"field1\":\"" + field1Val + "\"";
142 } else {
143 valueStr = valueStr + "{\"field1\":" + field1Val;
144 }
145
146 valueStr = valueStr + ",\"field2\":{\"field3\":" + fieldValue[index][INDEX_FIRST] + ",\"field4\":{\"field5\":" +
147 fieldValue[index][INDEX_SECOND] + ",\"field6\":{\"field7\":" + fieldValue[index][INDEX_THIRD] + ",\"field8\":" +
148 fieldValue[index][INDEX_FORTH] + "}}}}";
149 schemasValue.push_back(valueStr);
150 }
151 return schemasValue;
152 }
GenerateCombineSchemaEntries(std::vector<DistributedDB::Entry> & entries,const std::vector<vector<std::string>> & fieldValues,const std::vector<uint8_t> & keyPrefix,int startPoint)153 void DistributedDBSchemaTestTools::GenerateCombineSchemaEntries(std::vector<DistributedDB::Entry> &entries,
154 const std::vector<vector<std::string>> &fieldValues, const std::vector<uint8_t> &keyPrefix, int startPoint)
155 {
156 entries.clear();
157 vector<Key> keys;
158 int recordNo = fieldValues.size();
159 for (int cnt = startPoint; cnt < (startPoint + recordNo); cnt++) {
160 Key key = keyPrefix;
161 std::string keyNo = std::to_string(cnt);
162 key.insert(key.end(), keyNo.begin(), keyNo.end());
163 keys.push_back(key);
164 }
165 vector<string> valueStr = GenerateCombinationSchemaValue(fieldValues);
166 for (int index = 0; index < recordNo; index++) {
167 Entry entry;
168 Value value(valueStr[index].begin(), valueStr[index].end());
169 entry.key = keys[index];
170 entry.value = value;
171 entries.push_back(entry);
172 }
173 }
174
CombinationCheckQueryResult(KvStoreNbDelegate & delegate,const Query & query,vector<Entry> & expectEntry,const DBStatus status,bool canGetCount)175 bool DistributedDBSchemaTestTools::CombinationCheckQueryResult(KvStoreNbDelegate &delegate, const Query &query,
176 vector<Entry> &expectEntry, const DBStatus status, bool canGetCount)
177 {
178 vector<Entry> entries;
179 bool result = false;
180 result = (delegate.GetEntries(query, entries) == status);
181 if (!expectEntry.empty()) {
182 if (entries.size() != expectEntry.size()) {
183 MST_LOG("The entries from query is %zd, The expectEntry is %zd, they are not equal",
184 entries.size(), expectEntry.size());
185 return false;
186 }
187 for (vector<Entry>::size_type index = 0; index < entries.size(); index++) {
188 if (entries[index].key != expectEntry[index].key || entries[index].value != expectEntry[index].value) {
189 string keyGot(entries[index].key.begin(), entries[index].key.end());
190 string keyExpect(expectEntry[index].key.begin(), expectEntry[index].key.end());
191 MST_LOG("entry key compare failed, expectKey:%s, gotKey:%s, line:%d", keyExpect.c_str(), keyGot.c_str(),
192 __LINE__);
193 return false;
194 }
195 }
196 }
197 KvStoreResultSet *resultSet = nullptr;
198 if (status != NOT_FOUND) {
199 result = (delegate.GetEntries(query, resultSet) == status) && result;
200 } else {
201 result = (delegate.GetEntries(query, resultSet) == OK) && result;
202 if (resultSet != nullptr) {
203 Entry entry;
204 result = (resultSet->GetEntry(entry) == status) && result;
205 }
206 }
207 int expectCnt = expectEntry.size();
208 if (resultSet != nullptr) {
209 result = (resultSet->GetCount() == expectCnt) && result;
210 result = (delegate.CloseResultSet(resultSet) == DBStatus::OK) && result;
211 }
212 if (canGetCount) {
213 int cnt = 0;
214 result = (delegate.GetCount(query, cnt) == status) && result;
215 result = (cnt == expectCnt) && result;
216 }
217 return result;
218 }
219
GenSchemaValue(Value notSchemaValue)220 Value DistributedDBSchemaTestTools::GenSchemaValue(Value notSchemaValue)
221 {
222 // emit the first 'v' character
223 string notSchemaVal(notSchemaValue.begin() + INDEX_FIRST, notSchemaValue.end());
224 string valueRes = "{" + VALUE_MATCH_1 + "," + VALUE_MATCH_2 + ",\"field17\":" + notSchemaVal + "}";
225 Value valueSchema(valueRes.begin(), valueRes.end());
226 return valueSchema;
227 }
228
PreInsertRecords(KvStoreNbDelegate * & delegate,vector<Key> & keys,const std::vector<std::string> & values,int beginNumber)229 bool DistributedDBSchemaTestTools::PreInsertRecords(KvStoreNbDelegate *&delegate, vector<Key> &keys,
230 const std::vector<std::string> &values, int beginNumber)
231 {
232 bool result = true;
233 for (vector<string>::size_type index = 0; index < values.size(); index++) {
234 keys.push_back({'k', static_cast<uint8_t>(index + 49 + beginNumber)}); // 49 is the ASCII number of 'a'
235 }
236 for (vector<string>::size_type index = 0; index < values.size(); index++) {
237 Value value(values[index].begin(), values[index].end());
238 result = (DistributedDBNbTestTools::Put(*delegate, keys[index], value) == OK);
239 }
240 return result;
241 }
242
243 // insert query condition between brackets.
SpliceQueryMethod(int flag,Query & query)244 static void SpliceQueryMethod(int flag, Query &query)
245 {
246 switch (flag) {
247 case 0: // query condition 0
248 query.LessThan("$.field2.field4.field5", "100").And().NotEqualTo("$.field2.field4.field6.field7", "-100");
249 break;
250 case 1: // query condition 1
251 query.EqualTo("$.field2.field3", "true").Or().NotLike("$.field1", "%c");
252 break;
253 case 2: // query condition 2
254 query.Like("$.field1", "ab%");
255 break;
256 case 3: // query condition 3
257 query.GreaterThanOrEqualTo("$.field2.field4.field6.field8", "0");
258 break;
259 default: // other query condition
260 break;
261 }
262 }
263 // Generate rand query by the number of brackets.
GenerateRandQuery(Query & query,int beginNum,int endNum)264 void DistributedDBSchemaTestTools::GenerateRandQuery(Query &query, int beginNum, int endNum)
265 {
266 int left = 0;
267 int right = 0;
268 for (int cnt = 0; cnt < beginNum + endNum; cnt++) {
269 int bracketTest = GetRandInt(0, 1);
270 if (bracketTest == 0 && left < beginNum) {
271 left++;
272 if (cnt != 0) {
273 query.Or();
274 }
275 query.BeginGroup();
276 } else if (bracketTest == 1 && right < endNum) {
277 right++;
278 query.EndGroup();
279 } else {
280 cnt--;
281 continue;
282 }
283 int flag = GetRandInt(0, 4); // add query condition 0-4 to brackets.
284 if ((bracketTest == 0 && cnt < beginNum + endNum - 1) || (bracketTest == 1 && cnt == 0)) {
285 SpliceQueryMethod(flag, query);
286 } else if (bracketTest == 1 && cnt < beginNum + endNum - 1) {
287 query.And();
288 SpliceQueryMethod(flag, query);
289 }
290 }
291 }
292
TransformToSchemaEntry(std::vector<DistributedDB::Entry> & entries,const std::vector<DistributedDB::Key> & keys,const std::vector<std::string> & schemasValue)293 bool DistributedDBSchemaTestTools::TransformToSchemaEntry(std::vector<DistributedDB::Entry> &entries,
294 const std::vector<DistributedDB::Key> &keys, const std::vector<std::string> &schemasValue)
295 {
296 if (keys.size() != schemasValue.size()) {
297 MST_LOG("The number of keys is not equal to the value strings' number!");
298 return false;
299 }
300 for (vector<string>::size_type index = 0; index < schemasValue.size(); index++) {
301 Value value(schemasValue[index].begin(), schemasValue[index].end());
302 entries.push_back({keys[index], value});
303 }
304 return true;
305 }
306
GenerateSpecificSchemaEntries(const int startPoint,const int recordNumber,std::vector<DistributedDB::Entry> & entries,const std::vector<std::vector<std::string>> & values)307 void DistributedDBSchemaTestTools::GenerateSpecificSchemaEntries(const int startPoint, const int recordNumber,
308 std::vector<DistributedDB::Entry> &entries, const std::vector<std::vector<std::string>> &values)
309 {
310 entries.clear();
311 int switchFactor;
312 vector<Key> keys;
313 vector<string> schemasValue;
314 std::string indexNumStr, field1, field3, field5, field7, field8, value, switchFactorStr;
315 for (int indexNum = startPoint; indexNum < startPoint + recordNumber; indexNum++) {
316 indexNumStr = std::to_string(indexNum);
317 field1 = "\"field1\":\"SubscribeRemoteQueryTest" + indexNumStr + "\"";
318 field3 = "\"field3\":false";
319 field5 = "\"field5\":" + indexNumStr;
320 field7 = "\"field7\":" + indexNumStr;
321 field8 = "\"field8\":" + indexNumStr + ".1234";
322 for (auto &iter : values) {
323 switchFactorStr = iter[INDEX_ZEROTH];
324 switchFactor = switchFactorStr.back() - '0';
325 switch (switchFactor) {
326 case 1: // field 1 has assigned value
327 field1 = "\"field1\":\"" + iter[INDEX_FIRST] + "\"";
328 break;
329 case 3: // field 3 has assigned value
330 field3 = "\"field3\":" + iter[INDEX_FIRST];
331 break;
332 case 5: // field 5 has assigned value
333 field5 = "\"field5\":" + iter[INDEX_FIRST];
334 break;
335 case 7: // field 7 has assigned value
336 field7 = "\"field7\":" + iter[INDEX_FIRST];
337 break;
338 case 8: // field 8 has assigned value
339 field8 = "\"field8\":" + iter[INDEX_FIRST];
340 break;
341 default:
342 MST_LOG("invalid field !");
343 break;
344 }
345 }
346 value = "{" + field1 + ",\"field2\":{" + field3 + ",\"field4\":{" + field5 + ",\"field6\":{"
347 + field7 + "," + field8 + "}}}}";
348 indexNumStr = "k" + indexNumStr;
349 Key key(indexNumStr.begin(), indexNumStr.end());
350 keys.push_back(key);
351 schemasValue.push_back(value);
352 }
353 DistributedDBSchemaTestTools::TransformToSchemaEntry(entries, keys, schemasValue);
354 }
355