1 /*
2  * Copyright (c) 2022 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 <gtest/gtest.h>
18 #include <cmath>
19 
20 #include "db_errno.h"
21 #include "distributeddb_tools_unit_test.h"
22 #include "log_print.h"
23 #include "relational_schema_object.h"
24 #include "schema_utils.h"
25 #include "schema_constant.h"
26 #include "schema_negotiate.h"
27 
28 using namespace std;
29 using namespace testing::ext;
30 using namespace DistributedDB;
31 using namespace DistributedDBUnitTest;
32 
33 namespace {
34     constexpr const char* DB_SUFFIX = ".db";
35     constexpr const char* STORE_ID = "Relational_Store_ID";
36     string g_testDir;
37     string g_dbDir;
38 
39     const std::string NORMAL_SCHEMA = R""({
40             "SCHEMA_VERSION": "2.0",
41             "SCHEMA_TYPE": "RELATIVE",
42             "TABLES": [{
43                 "NAME": "FIRST",
44                 "DEFINE": {
45                     "field_name1": {
46                         "COLUMN_ID":1,
47                         "TYPE": "STRING",
48                         "NOT_NULL": true,
49                         "DEFAULT": "abcd"
50                     },
51                     "field_name2": {
52                         "COLUMN_ID":2,
53                         "TYPE": "MYINT(21)",
54                         "NOT_NULL": false,
55                         "DEFAULT": "222"
56                     },
57                     "field_name3": {
58                         "COLUMN_ID":3,
59                         "TYPE": "INTGER",
60                         "NOT_NULL": false,
61                         "DEFAULT": "1"
62                     }
63                 },
64                 "AUTOINCREMENT": true,
65                 "UNIQUE": [["field_name1"], ["field_name2", "field_name3"]],
66                 "PRIMARY_KEY": "field_name1",
67                 "INDEX": {
68                     "index_name1": ["field_name1", "field_name2"],
69                     "index_name2": ["field_name3"]
70                 }
71             }, {
72                 "NAME": "SECOND",
73                 "DEFINE": {
74                     "key": {
75                         "COLUMN_ID":1,
76                         "TYPE": "BLOB",
77                         "NOT_NULL": true
78                     },
79                     "value": {
80                         "COLUMN_ID":2,
81                         "TYPE": "BLOB",
82                         "NOT_NULL": false
83                     }
84                 },
85                 "PRIMARY_KEY": "field_name1"
86             }]
87         })"";
88 
89     const std::string NORMAL_SCHEMA_V2_1 = R""({
90             "SCHEMA_VERSION": "2.1",
91             "SCHEMA_TYPE": "RELATIVE",
92             "TABLE_MODE": "SPLIT_BY_DEVICE",
93             "TABLES": [{
94                 "NAME": "FIRST",
95                 "DEFINE": {
96                     "field_name1": {
97                         "COLUMN_ID":1,
98                         "TYPE": "STRING",
99                         "NOT_NULL": true,
100                         "DEFAULT": "abcd"
101                     },
102                     "field_name2": {
103                         "COLUMN_ID":2,
104                         "TYPE": "MYINT(21)",
105                         "NOT_NULL": false,
106                         "DEFAULT": "222"
107                     },
108                     "field_name3": {
109                         "COLUMN_ID":3,
110                         "TYPE": "INTGER",
111                         "NOT_NULL": false,
112                         "DEFAULT": "1"
113                     }
114                 },
115                 "AUTOINCREMENT": true,
116                 "UNIQUE": [["field_name1"], ["field_name2", "field_name3"]],
117                 "PRIMARY_KEY": ["field_name1", "field_name3"],
118                 "INDEX": {
119                     "index_name1": ["field_name1", "field_name2"],
120                     "index_name2": ["field_name3"]
121                 }
122             }, {
123                 "NAME": "SECOND",
124                 "DEFINE": {
125                     "key": {
126                         "COLUMN_ID":1,
127                         "TYPE": "BLOB",
128                         "NOT_NULL": true
129                     },
130                     "value": {
131                         "COLUMN_ID":2,
132                         "TYPE": "BLOB",
133                         "NOT_NULL": false
134                     }
135                 },
136                 "PRIMARY_KEY": ["field_name1"]
137             }]
138         })"";
139 
140     const std::string INVALID_SCHEMA = R""({
141             "SCHEMA_VERSION": "2.0",
142             "SCHEMA_TYPE": "RELATIVE",
143             "TABLES": [{
144                 "NAME": "FIRST",
145                 "DEFINE": {
146                     "field_name1": {
147                         "COLUMN_ID":1,
148                         "TYPE": "STRING",
149                         "NOT_NULL": true,
150                         "DEFAULT": "abcd"
151                     },"field_name2": {
152                         "COLUMN_ID":2,
153                         "TYPE": "MYINT(21)",
154                         "NOT_NULL": false,
155                         "DEFAULT": "222"
156                     }
157                 },
158                 "PRIMARY_KEY": "field_name1"
159             }]
160         })"";
161 
162     const std::string INVALID_JSON_STRING = R""({
163             "SCHEMA_VERSION": "2.0",
164             "SCHEMA_TYPE": "RELATIVE",
165             "TABLES": [{
166                 "NAME": "FIRST",
167                 "DEFINE": {
168                     "field_name1": {)"";
169 
170     const std::string SCHEMA_VERSION_STR_1 = R"("SCHEMA_VERSION": "1.0",)";
171     const std::string SCHEMA_VERSION_STR_2 = R"("SCHEMA_VERSION": "2.0",)";
172     const std::string SCHEMA_VERSION_STR_2_1 = R"("SCHEMA_VERSION": "2.1",)";
173     const std::string SCHEMA_VERSION_STR_INVALID = R"("SCHEMA_VERSION": "awd3",)";
174     const std::string SCHEMA_TYPE_STR_NONE = R"("SCHEMA_TYPE": "NONE",)";
175     const std::string SCHEMA_TYPE_STR_JSON = R"("SCHEMA_TYPE": "JSON",)";
176     const std::string SCHEMA_TYPE_STR_FLATBUFFER = R"("SCHEMA_TYPE": "FLATBUFFER",)";
177     const std::string SCHEMA_TYPE_STR_RELATIVE = R"("SCHEMA_TYPE": "RELATIVE",)";
178     const std::string SCHEMA_TYPE_STR_INVALID = R"("SCHEMA_TYPE": "adewaaSAD",)";
179     const std::string SCHEMA_TABLE_MODE_COLLABORATION = R"("TABLE_MODE": "COLLABORATION",)";
180     const std::string SCHEMA_TABLE_MODE_SPLIT_BY_DEVICE = R"("TABLE_MODE": "SPLIT_BY_DEVICE",)";
181     const std::string SCHEMA_TABLE_MODE_INVALID = R"("TABLE_MODE": "SPLIT_BY_USER",)";
182 
183     const std::string SCHEMA_TABLE_STR = R""("TABLES": [{
184             "NAME": "FIRST",
185             "DEFINE": {
186                 "field_name1": {
187                     "COLUMN_ID":1,
188                     "TYPE": "STRING",
189                     "NOT_NULL": true,
190                     "DEFAULT": "abcd"
191                 },"field_name2": {
192                     "COLUMN_ID":2,
193                     "TYPE": "MYINT(21)",
194                     "NOT_NULL": false,
195                     "DEFAULT": "222"
196                 }
197             },
198             "PRIMARY_KEY": "field_name1"
199         }])"";
200 
201     const std::string TABLE_DEFINE_STR = R""({
202         "NAME": "FIRST",
203         "DEFINE": {
204             "field_name1": {
205                 "COLUMN_ID":1,
206                 "TYPE": "STRING",
207                 "NOT_NULL": true,
208                 "DEFAULT": "abcd"
209             },"field_name2": {
210                 "COLUMN_ID":2,
211                 "TYPE": "MYINT(21)",
212                 "NOT_NULL": false,
213                 "DEFAULT": "222"
214             }
215         },
216         "PRIMARY_KEY": "field_name1"
217     })"";
218 
219     const std::string TABLE_DEFINE_STR_NAME = R""("NAME": "FIRST",)"";
220     const std::string TABLE_DEFINE_STR_NAME_INVALID = R"("NAME": 123,)";
221     const std::string TABLE_DEFINE_STR_NAME_INVALID_CHARACTER = R"("NAME": "t1; --",)";
222     const std::string TABLE_DEFINE_STR_FIELDS = R""("DEFINE": {
223             "field_name1": {
224                 "COLUMN_ID":1,
225                 "TYPE": "STRING",
226                 "NOT_NULL": true,
227                 "DEFAULT": "abcd"
228             },"field_name2": {
229                 "COLUMN_ID":2,
230                 "TYPE": "MYINT(21)",
231                 "NOT_NULL": false,
232                 "DEFAULT": "222"
233             }
234         },)"";
235     const std::string TABLE_DEFINE_STR_FIELDS_EMPTY = R""("DEFINE": {},)"";
236     const std::string TABLE_DEFINE_STR_FIELDS_NOTYPE = R""("DEFINE": {
237             "field_name1": {
238                 "COLUMN_ID":1,
239                 "NOT_NULL": true,
240                 "DEFAULT": "abcd"
241             }},)"";
242     const std::string TABLE_DEFINE_STR_FIELDS_INVALID_CHARACTER = R""("DEFINE": {
243             "1 = 1; --": {
244                 "COLUMN_ID":1,
245                 "NOT_NULL": true,
246                 "DEFAULT": "abcd"
247             }},)"";
248     const std::string TABLE_DEFINE_STR_KEY = R""("PRIMARY_KEY": "field_name1")"";
249     const std::string TABLE_DEFINE_BOOL_KEY_INVALID = R""("PRIMARY_KEY": false)"";
250     const std::string TABLE_DEFINE_BOOL_ARRAY_KEY_INVALID = R""("PRIMARY_KEY": [false, true, true])"";
251 }
252 
253 class DistributedDBRelationalSchemaObjectTest : public testing::Test {
254 public:
255     static void SetUpTestCase(void);
256     static void TearDownTestCase(void);
257     void SetUp() override;
258     void TearDown() override;
259 };
260 
SetUpTestCase(void)261 void DistributedDBRelationalSchemaObjectTest::SetUpTestCase(void)
262 {
263     DistributedDBToolsUnitTest::TestDirInit(g_testDir);
264     DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
265     LOGI("The test db is:%s", g_testDir.c_str());
266     g_dbDir = g_testDir + "/";
267 }
268 
TearDownTestCase(void)269 void DistributedDBRelationalSchemaObjectTest::TearDownTestCase(void)
270 {
271 }
272 
SetUp()273 void DistributedDBRelationalSchemaObjectTest::SetUp()
274 {
275     DistributedDBToolsUnitTest::PrintTestCaseInfo();
276 }
277 
TearDown()278 void DistributedDBRelationalSchemaObjectTest::TearDown()
279 {
280     if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
281         LOGE("rm test db files error.");
282     }
283     return;
284 }
285 
286 /**
287  * @tc.name: RelationalSchemaParseTest001
288  * @tc.desc: Test relational schema parse from json string
289  * @tc.type: FUNC
290  * @tc.require: AR000GK58I
291  * @tc.author: lianhuix
292  */
293 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest001, TestSize.Level1)
294 {
295     const std::string schemaStr = NORMAL_SCHEMA;
296     RelationalSchemaObject schemaObj;
297     int errCode = schemaObj.ParseFromSchemaString(schemaStr);
298     EXPECT_EQ(errCode, E_OK);
299     EXPECT_EQ(schemaObj.GetTable("FIRST").GetUniqueDefine().size(), 2u);
300 
301     RelationalSchemaObject schemaObj2;
302     schemaObj2.ParseFromSchemaString(schemaObj.ToSchemaString());
303     EXPECT_EQ(errCode, E_OK);
304     EXPECT_EQ(schemaObj2.GetTable("FIRST").GetUniqueDefine().size(), 2u);
305 
306     RelationalSyncOpinion op = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, schemaObj2.ToSchemaString(),
307         static_cast<uint8_t>(SchemaType::RELATIVE));
308 
309     EXPECT_EQ(op.size(), 2u);
310     EXPECT_EQ(op.at("FIRST").permitSync, true);
311     EXPECT_EQ(op.at("SECOND").permitSync, true);
312 }
313 
314 /**
315  * @tc.name: RelationalSchemaParseTest002
316  * @tc.desc: Test relational schema parse from invalid json string
317  * @tc.type: FUNC
318  * @tc.require: AR000GK58I
319  * @tc.author: lianhuix
320  */
321 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest002, TestSize.Level1)
322 {
323     RelationalSchemaObject schemaObj;
324 
325     std::string schemaStr01(SchemaConstant::SCHEMA_STRING_SIZE_LIMIT + 1, 's');
326     int errCode = schemaObj.ParseFromSchemaString(schemaStr01);
327     EXPECT_EQ(errCode, -E_INVALID_ARGS);
328 
329     errCode = schemaObj.ParseFromSchemaString(INVALID_JSON_STRING);
330     EXPECT_EQ(errCode, -E_JSON_PARSE_FAIL);
331 
332     std::string noVersion = "{" + SCHEMA_TYPE_STR_RELATIVE + SCHEMA_TABLE_STR + "}";
333     errCode = schemaObj.ParseFromSchemaString(noVersion);
334     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
335 
336     std::string invalidVersion1 = "{" + SCHEMA_VERSION_STR_1  + SCHEMA_TYPE_STR_RELATIVE + SCHEMA_TABLE_STR + "}";
337     errCode = schemaObj.ParseFromSchemaString(invalidVersion1);
338     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
339 
340     std::string invalidVersion2 = "{" + SCHEMA_VERSION_STR_INVALID  + SCHEMA_TYPE_STR_RELATIVE + SCHEMA_TABLE_STR + "}";
341     errCode = schemaObj.ParseFromSchemaString(invalidVersion2);
342     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
343 
344     std::string noType = "{" + SCHEMA_VERSION_STR_2 + SCHEMA_TABLE_STR + "}";
345     errCode = schemaObj.ParseFromSchemaString(noType);
346     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
347 
348     std::string invalidType1 = "{" + SCHEMA_VERSION_STR_2 + SCHEMA_TYPE_STR_NONE + SCHEMA_TABLE_STR + "}";
349     errCode = schemaObj.ParseFromSchemaString(invalidType1);
350     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
351 
352     std::string invalidType2 = "{" + SCHEMA_VERSION_STR_2 + SCHEMA_TYPE_STR_JSON + SCHEMA_TABLE_STR + "}";
353     errCode = schemaObj.ParseFromSchemaString(invalidType2);
354     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
355 
356     std::string invalidType3 = "{" + SCHEMA_VERSION_STR_2 + SCHEMA_TYPE_STR_FLATBUFFER + SCHEMA_TABLE_STR + "}";
357     errCode = schemaObj.ParseFromSchemaString(invalidType3);
358     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
359 
360     std::string invalidType4 = "{" + SCHEMA_VERSION_STR_2 + SCHEMA_TYPE_STR_INVALID + SCHEMA_TABLE_STR + "}";
361     errCode = schemaObj.ParseFromSchemaString(invalidType4);
362     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
363 
364     std::string noTable = "{" + SCHEMA_VERSION_STR_2 +
365         SCHEMA_TYPE_STR_RELATIVE.substr(0, SCHEMA_TYPE_STR_RELATIVE.length() - 1) + "}";
366     errCode = schemaObj.ParseFromSchemaString(noTable);
367     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
368 }
369 
370 namespace {
GenerateFromTableStr(const std::string & tableStr)371 std::string GenerateFromTableStr(const std::string &tableStr)
372 {
373     return R""({
374         "SCHEMA_VERSION": "2.0",
375         "SCHEMA_TYPE": "RELATIVE",
376         "TABLES": )"" + tableStr + "}";
377 }
378 }
379 
380 /**
381  * @tc.name: RelationalSchemaParseTest003
382  * @tc.desc: Test relational schema parse from invalid json string
383  * @tc.type: FUNC
384  * @tc.require: AR000GK58I
385  * @tc.author: lianhuix
386  */
387 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest003, TestSize.Level1)
388 {
389     RelationalSchemaObject schemaObj;
390     int errCode = E_OK;
391 
392     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr(TABLE_DEFINE_STR));
393     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
394 
395     std::string invalidTableStr01 = "{" + TABLE_DEFINE_STR_FIELDS + TABLE_DEFINE_STR_KEY + "}";
396     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr01 + "]"));
397     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
398 
399     std::string invalidTableStr02 = "{" + TABLE_DEFINE_STR_NAME_INVALID + TABLE_DEFINE_STR_FIELDS +
400         TABLE_DEFINE_STR_KEY + "}";
401     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr02 + "]"));
402     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
403 
404     std::string invalidTableStr04 = "{" + TABLE_DEFINE_STR_NAME + TABLE_DEFINE_STR_FIELDS_NOTYPE +
405         TABLE_DEFINE_STR_KEY + "}";
406     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr04 + "]"));
407     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
408 
409     std::string invalidTableStr05 = "{" + TABLE_DEFINE_STR_NAME + TABLE_DEFINE_STR_FIELDS +
410         TABLE_DEFINE_BOOL_KEY_INVALID + "}";
411     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr05 + "]"));
412     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
413 
414     std::string invalidTableStr06 = "{" + TABLE_DEFINE_STR_NAME + TABLE_DEFINE_STR_FIELDS +
415         TABLE_DEFINE_BOOL_ARRAY_KEY_INVALID + "}";
416     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr06 + "]"));
417     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
418 
419     std::string invalidTableStr07 = "{" + TABLE_DEFINE_STR_NAME_INVALID_CHARACTER + TABLE_DEFINE_STR_FIELDS +
420         TABLE_DEFINE_STR_KEY + "}";
421     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr07 + "]"));
422     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
423 
424     std::string invalidTableStr08 = "{" + TABLE_DEFINE_STR_NAME + TABLE_DEFINE_STR_FIELDS_INVALID_CHARACTER +
425         TABLE_DEFINE_STR_KEY + "}";
426     errCode = schemaObj.ParseFromSchemaString(GenerateFromTableStr("[" + invalidTableStr08 + "]"));
427     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
428 
429     errCode = schemaObj.ParseFromSchemaString("");
430     EXPECT_EQ(errCode, -E_INVALID_ARGS);
431 }
432 
433 /**
434  * @tc.name: RelationalSchemaParseTest004
435  * @tc.desc:
436  * @tc.type: FUNC
437  * @tc.require:
438  * @tc.author: lianhuix
439  */
440 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest004, TestSize.Level1)
441 {
442     RelationalSchemaObject schemaObj;
443     int errCode = E_OK;
444 
445     std::string schema = "{" + SCHEMA_VERSION_STR_2_1 + SCHEMA_TABLE_MODE_COLLABORATION + SCHEMA_TYPE_STR_RELATIVE +
446         SCHEMA_TABLE_STR + "}";
447     errCode = schemaObj.ParseFromSchemaString(schema);
448     EXPECT_EQ(errCode, E_OK);
449 }
450 
451 /**
452  * @tc.name: RelationalSchemaParseTest005
453  * @tc.desc:
454  * @tc.type: FUNC
455  * @tc.require:
456  * @tc.author: lianhuix
457  */
458 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest005, TestSize.Level1)
459 {
460     RelationalSchemaObject schemaObj;
461     int errCode = E_OK;
462 
463     std::string schema = "{" + SCHEMA_VERSION_STR_2_1 + SCHEMA_TABLE_MODE_SPLIT_BY_DEVICE + SCHEMA_TYPE_STR_RELATIVE +
464         SCHEMA_TABLE_STR + "}";
465     errCode = schemaObj.ParseFromSchemaString(schema);
466     EXPECT_EQ(errCode, E_OK);
467 }
468 
469 /**
470  * @tc.name: RelationalSchemaParseTest006
471  * @tc.desc:
472  * @tc.type: FUNC
473  * @tc.require:
474  * @tc.author: lianhuix
475  */
476 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaParseTest006, TestSize.Level1)
477 {
478     RelationalSchemaObject schemaObj;
479     int errCode = E_OK;
480 
481     std::string schema = "{" + SCHEMA_VERSION_STR_2_1 + SCHEMA_TABLE_MODE_INVALID + SCHEMA_TYPE_STR_RELATIVE +
482         SCHEMA_TABLE_STR + "}";
483     errCode = schemaObj.ParseFromSchemaString(schema);
484     EXPECT_EQ(errCode, -E_SCHEMA_PARSE_FAIL);
485 }
486 
487 
488 /**
489  * @tc.name: RelationalSchemaCompareTest001
490  * @tc.desc: Test relational schema negotiate with same schema string
491  * @tc.type: FUNC
492  * @tc.require: AR000GK58I
493  * @tc.author: lianhuix
494  */
495 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaCompareTest001, TestSize.Level1)
496 {
497     RelationalSchemaObject schemaObj;
498     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA);
499     EXPECT_EQ(errCode, E_OK);
500 
501     RelationalSyncOpinion opinion = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, NORMAL_SCHEMA,
502         static_cast<uint8_t>(SchemaType::RELATIVE));
503     EXPECT_EQ(opinion.at("FIRST").permitSync, true);
504     EXPECT_EQ(opinion.at("FIRST").checkOnReceive, false);
505     EXPECT_EQ(opinion.at("FIRST").requirePeerConvert, false);
506 }
507 
508 /**
509  * @tc.name: RelationalSchemaCompareTest002
510  * @tc.desc: Test relational schema v2.1 negotiate with same schema string
511  * @tc.type: FUNC
512  * @tc.require: AR000H2PKN
513  * @tc.author: lianhuix
514  */
515 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaCompareTest002, TestSize.Level1)
516 {
517     RelationalSchemaObject schemaObj;
518     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA_V2_1);
519     EXPECT_EQ(errCode, E_OK);
520 
521     RelationalSyncOpinion opinion = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, NORMAL_SCHEMA_V2_1,
522         static_cast<uint8_t>(SchemaType::RELATIVE));
523     EXPECT_EQ(opinion.at("FIRST").permitSync, true);
524     EXPECT_EQ(opinion.at("FIRST").checkOnReceive, false);
525     EXPECT_EQ(opinion.at("FIRST").requirePeerConvert, false);
526 }
527 
528 /**
529  * @tc.name: RelationalSchemaCompareTest003
530  * @tc.desc: Test relational schema v2.1 negotiate with schema v2.0
531  * @tc.type: FUNC
532  * @tc.require: AR000H2PKN
533  * @tc.author: lianhuix
534  */
535 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaCompareTest003, TestSize.Level1)
536 {
537     RelationalSchemaObject schemaObj;
538     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA_V2_1);
539     EXPECT_EQ(errCode, E_OK);
540 
541     RelationalSyncOpinion opinion = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, NORMAL_SCHEMA,
542         static_cast<uint8_t>(SchemaType::RELATIVE));
543     EXPECT_TRUE(opinion.empty());
544 }
545 
546 /**
547  * @tc.name: RelationalSchemaCompareTest004
548  * @tc.desc: Test relational schema v2.0 negotiate with schema v2.1
549  * @tc.type: FUNC
550  * @tc.require: AR000H2PKN
551  * @tc.author: lianhuix
552  */
553 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaCompareTest004, TestSize.Level1)
554 {
555     RelationalSchemaObject schemaObj;
556     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA);
557     EXPECT_EQ(errCode, E_OK);
558 
559     RelationalSyncOpinion opinion = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, NORMAL_SCHEMA_V2_1,
560         static_cast<uint8_t>(SchemaType::RELATIVE));
561     EXPECT_TRUE(opinion.empty());
562 }
563 
564 /**
565  * @tc.name: RelationalSchemaCompareTest005
566  * @tc.desc: Test collaboration relational schema negotiate with other table mode
567  * @tc.type: FUNC
568  * @tc.require: AR000H2PKN
569  * @tc.author: lianhuix
570  */
571 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaCompareTest005, TestSize.Level1)
572 {
573     RelationalSchemaObject schemaObj;
574     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA_V2_1);
575     EXPECT_EQ(errCode, E_OK);
576     schemaObj.SetTableMode(DistributedTableMode::COLLABORATION);
577 
578     RelationalSyncOpinion opinion = SchemaNegotiate::MakeLocalSyncOpinion(schemaObj, NORMAL_SCHEMA_V2_1,
579         static_cast<uint8_t>(SchemaType::RELATIVE));
580     EXPECT_TRUE(opinion.empty());
581 }
582 
583 /**
584  * @tc.name: RelationalTableCompareTest001
585  * @tc.desc: Test relational schema negotiate with same schema string
586  * @tc.type: FUNC
587  * @tc.require: AR000GK58I
588  * @tc.author: lianhuix
589  */
590 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalTableCompareTest001, TestSize.Level1)
591 {
592     RelationalSchemaObject schemaObj;
593     int errCode = schemaObj.ParseFromSchemaString(NORMAL_SCHEMA);
594     EXPECT_EQ(errCode, E_OK);
595     TableInfo table1 = schemaObj.GetTable("FIRST");
596     TableInfo table2 = schemaObj.GetTable("FIRST");
597     EXPECT_EQ(table1.CompareWithTable(table2), -E_RELATIONAL_TABLE_EQUAL);
598 
599     table2.AddIndexDefine("indexname", {"field_name2", "field_name1"});
600     EXPECT_EQ(table1.CompareWithTable(table2), -E_RELATIONAL_TABLE_COMPATIBLE);
601 
602     TableInfo table3 = schemaObj.GetTable("SECOND");
603     EXPECT_EQ(table1.CompareWithTable(table3), -E_RELATIONAL_TABLE_INCOMPATIBLE);
604 
605     TableInfo table4 = schemaObj.GetTable("FIRST");
606     table4.AddField(table3.GetFields().at("value"));
607     EXPECT_EQ(table1.CompareWithTable(table4), -E_RELATIONAL_TABLE_COMPATIBLE_UPGRADE);
608 
609     TableInfo table5 = schemaObj.GetTable("FIRST");
610     table5.AddField(table3.GetFields().at("key"));
611     EXPECT_EQ(table1.CompareWithTable(table5), -E_RELATIONAL_TABLE_INCOMPATIBLE);
612 
613     TableInfo table6 = schemaObj.GetTable("FIRST");
614     table6.SetUniqueDefine({{"field_name1", "field_name1"}});
615     EXPECT_EQ(table1.CompareWithTable(table6, SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1),
616         -E_RELATIONAL_TABLE_INCOMPATIBLE);
617 
618     TableInfo table7 = schemaObj.GetTable("FIRST");
619     table7.SetAutoIncrement(false);
620     EXPECT_EQ(table1.CompareWithTable(table7, SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1),
621         -E_RELATIONAL_TABLE_INCOMPATIBLE);
622 }
623 
624 /**
625  * @tc.name: RelationalSchemaOpinionTest001
626  * @tc.desc: Test relational schema sync opinion
627  * @tc.type: FUNC
628  * @tc.require: AR000GK58I
629  * @tc.author: lianhuix
630  */
631 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaOpinionTest001, TestSize.Level1)
632 {
633     RelationalSyncOpinion opinion;
634     opinion["table_1"] = SyncOpinion {true, false, false};
635     opinion["table_2"] = SyncOpinion {false, true, false};
636     opinion["table_3"] = SyncOpinion {false, false, true};
637 
638     uint32_t len = SchemaNegotiate::CalculateParcelLen(opinion);
639     std::vector<uint8_t> buff(len, 0);
640     Parcel writeParcel(buff.data(), len);
641     int errCode = SchemaNegotiate::SerializeData(opinion, writeParcel);
642     EXPECT_EQ(errCode, E_OK);
643 
644     Parcel readParcel(buff.data(), len);
645     RelationalSyncOpinion opinionRecv;
646     errCode = SchemaNegotiate::DeserializeData(readParcel, opinionRecv);
647     EXPECT_EQ(errCode, E_OK);
648 
649     EXPECT_EQ(opinion.size(), opinionRecv.size());
650     for (const auto &it : opinion) {
651         SyncOpinion tableOpinionRecv = opinionRecv.at(it.first);
652         EXPECT_EQ(it.second.permitSync, tableOpinionRecv.permitSync);
653         EXPECT_EQ(it.second.requirePeerConvert, tableOpinionRecv.requirePeerConvert);
654     }
655 }
656 
657 /**
658  * @tc.name: RelationalSchemaNegotiateTest001
659  * @tc.desc: Test relational schema negotiate
660  * @tc.type: FUNC
661  * @tc.require: AR000GK58I
662  * @tc.author: lianhuix
663  */
664 HWTEST_F(DistributedDBRelationalSchemaObjectTest, RelationalSchemaNegotiateTest001, TestSize.Level1)
665 {
666     RelationalSyncOpinion localOpinion;
667     localOpinion["table_1"] = SyncOpinion {true, false, false};
668     localOpinion["table_2"] = SyncOpinion {false, true, false};
669     localOpinion["table_3"] = SyncOpinion {false, false, true};
670 
671     RelationalSyncOpinion remoteOpinion;
672     remoteOpinion["table_2"] = SyncOpinion {true, false, false};
673     remoteOpinion["table_3"] = SyncOpinion {false, true, false};
674     remoteOpinion["table_4"] = SyncOpinion {false, false, true};
675     RelationalSyncStrategy strategy = SchemaNegotiate::ConcludeSyncStrategy(localOpinion, remoteOpinion);
676 
677     EXPECT_EQ(strategy.size(), 2u);
678     EXPECT_EQ(strategy.at("table_2").permitSync, true);
679     EXPECT_EQ(strategy.at("table_3").permitSync, false);
680 }
681 
682 /**
683  * @tc.name: TableCompareTest001
684  * @tc.desc: Test table compare
685  * @tc.type: FUNC
686  * @tc.require: AR000GK58I
687  * @tc.author: lianhuix
688  */
689 HWTEST_F(DistributedDBRelationalSchemaObjectTest, TableCompareTest001, TestSize.Level1)
690 {
691     FieldInfo field1;
692     field1.SetFieldName("a");
693     FieldInfo field2;
694     field2.SetFieldName("b");
695     FieldInfo field3;
696     field3.SetFieldName("c");
697     FieldInfo field4;
698     field4.SetFieldName("d");
699 
700     TableInfo table;
701     table.AddField(field2);
702     table.AddField(field3);
703 
704     TableInfo inTable1;
705     inTable1.AddField(field1);
706     inTable1.AddField(field2);
707     inTable1.AddField(field3);
708     EXPECT_EQ(table.CompareWithTable(inTable1), -E_RELATIONAL_TABLE_COMPATIBLE_UPGRADE);
709 
710     TableInfo inTable2;
711     inTable2.AddField(field1);
712     inTable2.AddField(field2);
713     inTable2.AddField(field4);
714     EXPECT_EQ(table.CompareWithTable(inTable2), -E_RELATIONAL_TABLE_INCOMPATIBLE);
715 
716     TableInfo inTable3;
717     inTable3.AddField(field3);
718     inTable3.AddField(field2);
719     EXPECT_EQ(table.CompareWithTable(inTable3), -E_RELATIONAL_TABLE_EQUAL);
720 }
721 
722 HWTEST_F(DistributedDBRelationalSchemaObjectTest, TableCaseInsensitiveCompareTest001, TestSize.Level1)
723 {
724     sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
725     EXPECT_NE(db, nullptr);
726     EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
727     std::string createStudentSql = "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT, score INT, level INT)";
728     EXPECT_EQ(RelationalTestUtils::ExecSql(db, createStudentSql), SQLITE_OK);
729 
730     TableInfo tableStudent;
731     EXPECT_EQ(SQLiteUtils::AnalysisSchema(db, "STUDENT", tableStudent), E_OK);
732 
733     RelationalSchemaObject schema;
734     schema.AddRelationalTable(tableStudent);
735 
736     EXPECT_FALSE(schema.GetTable("STUDENT").Empty());
737     EXPECT_FALSE(schema.GetTable("StudENT").Empty());
738     EXPECT_EQ(schema.GetTable("StudENT").CompareWithTable(schema.GetTable("STUDENT")), -E_RELATIONAL_TABLE_EQUAL);
739 
740     EXPECT_EQ(sqlite3_close_v2(db), E_OK);
741 }
742 
743 namespace {
GetTableInfo(sqlite3 * db,const std::string & tableName,const std::string & sql)744 TableInfo GetTableInfo(sqlite3 *db, const std::string &tableName, const std::string &sql)
745 {
746     EXPECT_NE(db, nullptr);
747     EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
748     TableInfo tableInfo;
749     EXPECT_EQ(SQLiteUtils::AnalysisSchema(db, tableName, tableInfo), E_OK);
750     EXPECT_EQ(RelationalTestUtils::ExecSql(db, "DROP TABLE IF EXISTS " + tableName), SQLITE_OK);
751     return tableInfo;
752 }
753 }
754 
755 HWTEST_F(DistributedDBRelationalSchemaObjectTest, TableCaseInsensitiveCompareTest002, TestSize.Level1)
756 {
757     sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
758     EXPECT_NE(db, nullptr);
759     EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
760 
761     std::string createTableSql1 = "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT, score INT, level INT); " \
762         "create index index_name on student (name);";
763     TableInfo table1 = GetTableInfo(db, "student", createTableSql1);
764     std::string createTableSql2 = "CREATE TABLE Student(ID INTEGER PRIMARY KEY, Name TEXT, Score INT, Level INT); " \
765         "create index index_NAME on student (Name);";
766     TableInfo table2 = GetTableInfo(db, "Student", createTableSql2);
767 
768     EXPECT_EQ(table1.CompareWithTable(table2), -E_RELATIONAL_TABLE_EQUAL);
769 
770     EXPECT_EQ(sqlite3_close_v2(db), E_OK);
771     db = nullptr;
772 }
773 
774 namespace {
TableCompareTest(sqlite3 * db,const std::string & sql1,const std::string & sql2)775 int TableCompareTest(sqlite3 *db, const std::string &sql1, const std::string &sql2)
776 {
777     RelationalTestUtils::ExecSql(db, sql1);
778     TableInfo table1;
779     SQLiteUtils::AnalysisSchema(db, "student", table1);
780     RelationalTestUtils::ExecSql(db, "DROP TABLE IF EXISTS student");
781     RelationalTestUtils::ExecSql(db, sql2);
782     TableInfo table2;
783     SQLiteUtils::AnalysisSchema(db, "student", table2);
784     RelationalTestUtils::ExecSql(db, "DROP TABLE IF EXISTS student");
785     return table1.CompareWithTable(table2);
786 }
787 
788 /**
789  * @tc.name: TableCompareTest001
790  * @tc.desc: Test table compare with default value
791  * @tc.type: FUNC
792  * @tc.require: AR000GK58I
793  * @tc.author: lianhuix
794  */
795 HWTEST_F(DistributedDBRelationalSchemaObjectTest, TableCompareTest002, TestSize.Level1)
796 {
797     sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX);
798     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
799         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)"),
800         -E_RELATIONAL_TABLE_EQUAL);
801     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
802         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'xue')"),
803         -E_RELATIONAL_TABLE_INCOMPATIBLE);
804     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
805         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT '')"),
806         -E_RELATIONAL_TABLE_INCOMPATIBLE);
807     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
808         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'NULL')"),
809         -E_RELATIONAL_TABLE_INCOMPATIBLE);
810     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
811         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'null')"),
812         -E_RELATIONAL_TABLE_INCOMPATIBLE);
813     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
814         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT NULL)"),
815         -E_RELATIONAL_TABLE_INCOMPATIBLE);
816     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT)",
817         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT null)"),
818         -E_RELATIONAL_TABLE_INCOMPATIBLE);
819     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'XUE')",
820         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'xue')"),
821         -E_RELATIONAL_TABLE_INCOMPATIBLE);
822     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT NULL)",
823         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT null)"),
824         -E_RELATIONAL_TABLE_EQUAL);
825     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'NULL')",
826         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT 'null')"),
827         -E_RELATIONAL_TABLE_INCOMPATIBLE);
828     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT '')",
829         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT NULL)"),
830         -E_RELATIONAL_TABLE_INCOMPATIBLE);
831     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT '')",
832         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT null)"),
833         -E_RELATIONAL_TABLE_INCOMPATIBLE);
834     EXPECT_EQ(TableCompareTest(db, "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT '')",
835         "CREATE TABLE student(id INTEGER PRIMARY KEY, name TEXT DEFAULT '')"),
836         -E_RELATIONAL_TABLE_EQUAL);
837     EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
838     db = nullptr;
839 }
840 } // namespace
841 
842 /**
843  * @tc.name: FieldInfoCompareTest
844  * @tc.desc: Test field info compare
845  * @tc.type: FUNC
846  * @tc.require: DTS2024073106613
847  * @tc.author: suyue
848  */
849 HWTEST_F(DistributedDBRelationalSchemaObjectTest, FieldInfoCompareTest, TestSize.Level1)
850 {
851     /**
852      * @tc.steps: step1. call CompareWithField when storageType is different
853      * @tc.expected: step1. return false.
854      */
855     FieldInfo field1;
856     field1.SetStorageType(StorageType::STORAGE_TYPE_INTEGER);
857     FieldInfo field2;
858     EXPECT_EQ(field2.CompareWithField(field1, true), false);
859 
860     /**
861      * @tc.steps: step2. call CompareWithField when fieldName is different
862      * @tc.expected: step2. return false.
863      */
864     field1.SetFieldName("test1");
865     field1.SetFieldName("test2");
866     EXPECT_EQ(field2.CompareWithField(field1, true), false);
867 }
868 
869 /**
870  * @tc.name: TableInfoInterfacesTest
871  * @tc.desc: Test TableInfo interfaces
872  * @tc.type: FUNC
873  * @tc.require: DTS2024073106613
874  * @tc.author: suyue
875  */
876 HWTEST_F(DistributedDBRelationalSchemaObjectTest, TableInfoInterfacesTest, TestSize.Level1)
877 {
878     /**
879      * @tc.steps: step1. GetFieldName with empty TableInfo class
880      * @tc.expected: step1. return empty string.
881      */
882     TableInfo table1;
883     std::string str1 = table1.GetFieldName(0);
884     const std::string expectStr1 = "";
885     EXPECT_TRUE(str1.compare(0, expectStr1.length(), expectStr1) == 0);
886     table1.ToTableInfoString("");
887 
888     /**
889      * @tc.steps: step2. Set and get tableId.
890      * @tc.expected: step2. success.
891      */
892     int inputId = 1;
893     table1.SetTableId(inputId);
894     int outputId = table1.GetTableId();
895     EXPECT_EQ(outputId, inputId);
896 }
897 
898 /**
899  * @tc.name: SchemaTableCompareTest
900  * @tc.desc: Test LiteSchemaTable Compare
901  * @tc.type: FUNC
902  * @tc.require: DTS2024073106613
903  * @tc.author: suyue
904  */
905 HWTEST_F(DistributedDBRelationalSchemaObjectTest, SchemaTableCompareTest, TestSize.Level1)
906 {
907     /**
908      * @tc.steps: step1. Set key index of SetPrimaryKey to an invalid value
909      * @tc.expected: step1. fieldName vector is null.
910      */
911     TableInfo table1;
912     int keyIndex = -1;
913     table1.SetPrimaryKey("test", keyIndex);
914     CompositeFields vec = table1.GetIdentifyKey();
915     uint32_t expectedVal = 0;
916     EXPECT_EQ(vec.size(), expectedVal);
917 
918     /**
919      * @tc.steps: step2. Compare table when fieldName of SetPrimaryKey is set to'rowid'
920      * @tc.expected: step2. compare return -E_RELATIONAL_TABLE_INCOMPATIBLE.
921      */
922     const std::vector<CompositeFields> uniqueDefine = {{"test0", "test1"}};
923     table1.SetUniqueDefine(uniqueDefine);
924     const std::map<int, FieldName> keyName1 = {{0, "rowid"}};
925     table1.SetPrimaryKey(keyName1);
926 
927     vec = table1.GetIdentifyKey();
928     EXPECT_EQ(vec.size(), uniqueDefine[0].size());
929     int ret = table1.CompareWithLiteSchemaTable(table1);
930     EXPECT_EQ(ret, -E_RELATIONAL_TABLE_INCOMPATIBLE);
931 
932     /**
933      * @tc.steps: step3. Compare table when fieldName of SetPrimaryKey is not set to "rowid".
934      * @tc.expected: step3. compare return E_OK.
935      */
936     FieldInfo field1;
937     table1.AddField(field1);
938     const std::map<int, FieldName> keyName2 = {{0, "test0"}, {1, "test1"}};
939     table1.SetPrimaryKey(keyName2);
940 
941     vec = table1.GetIdentifyKey();
942     EXPECT_EQ(vec.size(), keyName2.size());
943     field1.SetFieldName("test1");
944     ret = table1.CompareWithLiteSchemaTable(table1);
945     EXPECT_EQ(ret, E_OK);
946 }
947 #endif