1 /*
2 * Copyright (c) 2023 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 "cloud/schema_mgr.h"
16
17 #include <gtest/gtest.h>
18
19 #include "db_errno.h"
20 #include "distributeddb_tools_unit_test.h"
21 #include "relational_store_manager.h"
22 #include "relational_schema_object.h"
23 #include "distributeddb_data_generate_unit_test.h"
24 #include "relational_sync_able_storage.h"
25 #include "relational_store_instance.h"
26 #include "sqlite_relational_store.h"
27 #include "log_table_manager_factory.h"
28
29 using namespace testing::ext;
30 using namespace DistributedDB;
31 using namespace DistributedDBUnitTest;
32 using namespace std;
33
34 namespace {
35 constexpr auto TABLE_NAME_1 = "tableName1";
36 constexpr auto TABLE_NAME_2 = "tableName2";
37 constexpr auto TABLE_NAME_3 = "tableName3";
38 constexpr auto TABLE_NAME_4 = "tableName4";
39
40 constexpr auto FIELD_NAME_1 = "field_name_1";
41 constexpr auto FIELD_NAME_2 = "field_name_2";
42 constexpr auto FIELD_NAME_3 = "field_name_3";
43
44 std::unique_ptr<SchemaMgr> g_schemaMgr = nullptr;
45
46 class DistributedDBCloudSchemaMgrTest : public testing::Test {
47 public:
48 static void SetUpTestCase(void);
49 static void TearDownTestCase(void);
50 void SetUp();
51 void TearDown();
52 };
53
SetUpTestCase(void)54 void DistributedDBCloudSchemaMgrTest::SetUpTestCase(void)
55 {
56 }
57
TearDownTestCase(void)58 void DistributedDBCloudSchemaMgrTest::TearDownTestCase(void)
59 {
60 }
61
SetUp(void)62 void DistributedDBCloudSchemaMgrTest::SetUp(void)
63 {
64 g_schemaMgr = std::make_unique<SchemaMgr>();
65 }
66
TearDown(void)67 void DistributedDBCloudSchemaMgrTest::TearDown(void)
68 {
69 g_schemaMgr = nullptr;
70 }
71
72 DataBaseSchema g_schema = {
73 .tables = {
74 {
75 .name = TABLE_NAME_1,
76 .fields = {
77 {
78 .colName = FIELD_NAME_1,
79 .type = TYPE_INDEX<int64_t>,
80 .primary = true,
81 .nullable = true,
82 },
83 {
84 .colName = FIELD_NAME_2,
85 .type = TYPE_INDEX<int64_t>,
86 .primary = false,
87 .nullable = true,
88 }
89 }
90 },
91 {
92 .name = TABLE_NAME_2,
93 .fields = {
94 {
95 .colName = FIELD_NAME_1,
96 .type = TYPE_INDEX<int64_t>,
97 .primary = true,
98 .nullable = true,
99 },
100 {
101 .colName = FIELD_NAME_2,
102 .type = TYPE_INDEX<int64_t>,
103 .primary = false,
104 .nullable = true,
105 }
106 }
107 },
108 {
109 .name = TABLE_NAME_3,
110 .fields = {
111 {
112 .colName = FIELD_NAME_1,
113 .type = TYPE_INDEX<Asset>,
114 .primary = true,
115 .nullable = true,
116 },
117 {
118 .colName = FIELD_NAME_2,
119 .type = TYPE_INDEX<std::string>,
120 .primary = false,
121 .nullable = true,
122 },
123 {
124 .colName = FIELD_NAME_3,
125 .type = TYPE_INDEX<int64_t>,
126 .primary = false,
127 .nullable = true,
128 }
129 }
130 },
131 {
132 .name = TABLE_NAME_4,
133 .fields = {
134 {
135 .colName = FIELD_NAME_1,
136 .type = TYPE_INDEX<Assets>,
137 .primary = false,
138 .nullable = true,
139 },
140 {
141 .colName = FIELD_NAME_2,
142 .type = TYPE_INDEX<std::string>,
143 .primary = false,
144 .nullable = true,
145 },
146 {
147 .colName = FIELD_NAME_3,
148 .type = TYPE_INDEX<int64_t>,
149 .primary = false,
150 .nullable = true,
151 }
152 }
153 }
154 }
155 };
156
157 DataBaseSchema g_schema2 = {
158 .tables = {
159 {
160 .name = TABLE_NAME_2,
161 .fields = {
162 {
163 .colName = FIELD_NAME_1,
164 .type = TYPE_INDEX<int64_t>,
165 .primary = true,
166 .nullable = true,
167 },
168 {
169 .colName = FIELD_NAME_2,
170 .type = TYPE_INDEX<int64_t>,
171 .primary = false,
172 .nullable = true,
173 }
174 }
175 },
176 {
177 .name = TABLE_NAME_3,
178 .fields = {
179 {
180 .colName = FIELD_NAME_1,
181 .type = TYPE_INDEX<int64_t>,
182 .primary = true,
183 .nullable = true,
184 },
185 {
186 .colName = FIELD_NAME_2,
187 .type = TYPE_INDEX<int64_t>,
188 .primary = false,
189 .nullable = true,
190 }
191 }
192 },
193 {
194 .name = TABLE_NAME_4,
195 .fields = {
196 {
197 .colName = FIELD_NAME_1,
198 .type = TYPE_INDEX<int64_t>,
199 .primary = true,
200 .nullable = true,
201 },
202 {
203 .colName = FIELD_NAME_2,
204 .type = TYPE_INDEX<int64_t>,
205 .primary = false,
206 .nullable = true,
207 }
208 }
209 }
210 }
211 };
212
213
SetField(std::string fieldName,std::string dataType,bool nullable)214 FieldInfo SetField(std::string fieldName, std::string dataType, bool nullable)
215 {
216 FieldInfo field;
217 field.SetFieldName(fieldName);
218 field.SetDataType(dataType);
219 field.SetNotNull(!nullable);
220 return field;
221 }
222
223 /**
224 * @tc.name: SchemaMgrTest001
225 * @tc.desc: Cloud schema and local schema are not been set
226 * test situation: TABLE_NAME exist and not exist(TABLE_NAME_3)
227 * @tc.type: FUNC
228 * @tc.require:
229 * @tc.author: wanyi
230 */
231 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest001, TestSize.Level0)
232 {
233 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
234 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
235 TableInfo table;
236 table.SetTableName(TABLE_NAME_2);
237 table.AddField(field1);
238 table.AddField(field2);
239 table.SetPrimaryKey(FIELD_NAME_1, 1);
240 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
241 RelationalSchemaObject localSchema;
242 localSchema.AddRelationalTable(table);
243
244 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_1, localSchema), -E_SCHEMA_MISMATCH);
245 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_SCHEMA_MISMATCH);
246 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_3, localSchema), -E_SCHEMA_MISMATCH);
247 }
248
249 /**
250 * @tc.name: SchemaMgrTest002
251 * @tc.desc: Cloud schema and local schema are the same
252 * @tc.type: FUNC
253 * @tc.require:
254 * @tc.author: wanyi
255 */
256 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest002, TestSize.Level0)
257 {
258 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
259 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
260 TableInfo table;
261 table.SetTableName(TABLE_NAME_2);
262 table.AddField(field1);
263 table.AddField(field2);
264 table.SetPrimaryKey(FIELD_NAME_1, 1);
265 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
266 RelationalSchemaObject localSchema;
267 localSchema.AddRelationalTable(table);
268
269 g_schemaMgr->SetCloudDbSchema(g_schema);
270 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
271 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
272 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
273 }
274
275 /**
276 * @tc.name: SchemaMgrTest003
277 * @tc.desc: Local schema contain extra primary key
278 * @tc.type: FUNC
279 * @tc.require:
280 * @tc.author: wanyi
281 */
282 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest003, TestSize.Level0)
283 {
284 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
285 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
286 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
287
288 TableInfo table;
289 table.SetTableName(TABLE_NAME_2);
290 table.AddField(field1);
291 table.AddField(field2);
292 table.AddField(field3);
293 table.SetPrimaryKey(FIELD_NAME_1, 1);
294 table.SetPrimaryKey(FIELD_NAME_3, 2);
295 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
296 RelationalSchemaObject localSchema;
297 localSchema.AddRelationalTable(table);
298
299 g_schemaMgr->SetCloudDbSchema(g_schema);
300 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_SCHEMA_MISMATCH);
301 }
302
303 /**
304 * @tc.name: SchemaMgrTest003
305 * @tc.desc: Column from local schema is not within cloud schema but is not nullable
306 * @tc.type: FUNC
307 * @tc.require:
308 * @tc.author: wanyi
309 */
310 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest004, TestSize.Level0)
311 {
312 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
313 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
314 FieldInfo field3 = SetField(FIELD_NAME_2, "int", false);
315
316 TableInfo table;
317 table.SetTableName(TABLE_NAME_2);
318 table.AddField(field1);
319 table.AddField(field2);
320 table.AddField(field3);
321 table.SetPrimaryKey(FIELD_NAME_1, 1);
322 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
323 RelationalSchemaObject localSchema;
324 localSchema.AddRelationalTable(table);
325
326 g_schemaMgr->SetCloudDbSchema(g_schema);
327 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_SCHEMA_MISMATCH);
328 }
329
330 /**
331 * @tc.name: SchemaMgrTest003
332 * @tc.desc: Local schema contain extra noraml key with default value but cannot be null
333 * @tc.type: FUNC
334 * @tc.require:
335 * @tc.author: wanyi
336 */
337 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest005, TestSize.Level0)
338 {
339 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
340 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
341 FieldInfo field3 = SetField(FIELD_NAME_3, "int", false);
342 field3.SetDefaultValue("0");
343
344 TableInfo table;
345 table.SetTableName(TABLE_NAME_2);
346 table.AddField(field1);
347 table.AddField(field2);
348 table.AddField(field3);
349 table.SetPrimaryKey(FIELD_NAME_1, 1);
350 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
351 RelationalSchemaObject localSchema;
352 localSchema.AddRelationalTable(table);
353
354 g_schemaMgr->SetCloudDbSchema(g_schema);
355 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
356 }
357
358 /**
359 * @tc.name: SchemaMgrTest003
360 * @tc.desc: Local schema contain extra noraml key with default value but cannot be null
361 * @tc.type: FUNC
362 * @tc.require:
363 * @tc.author: wanyi
364 */
365 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest006, TestSize.Level0)
366 {
367 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
368 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
369 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
370 field3.SetDefaultValue("0");
371
372 TableInfo table;
373 table.SetTableName(TABLE_NAME_2);
374 table.AddField(field1);
375 table.AddField(field2);
376 table.AddField(field3);
377 table.SetPrimaryKey(FIELD_NAME_1, 1);
378 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
379 RelationalSchemaObject localSchema;
380 localSchema.AddRelationalTable(table);
381
382 g_schemaMgr->SetCloudDbSchema(g_schema);
383 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
384 }
385
386 /**
387 * @tc.name: SchemaMgrTest003
388 * @tc.desc: Local schema contain extra noraml key with default value but cannot be null
389 * @tc.type: FUNC
390 * @tc.require:
391 * @tc.author: wanyi
392 */
393 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest007, TestSize.Level0)
394 {
395 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
396 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
397 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
398
399 TableInfo table;
400 table.SetTableName(TABLE_NAME_2);
401 table.AddField(field1);
402 table.AddField(field2);
403 table.AddField(field3);
404 table.SetPrimaryKey(FIELD_NAME_1, 1);
405 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
406 RelationalSchemaObject localSchema;
407 localSchema.AddRelationalTable(table);
408
409 g_schemaMgr->SetCloudDbSchema(g_schema);
410 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), E_OK);
411 }
412
413 /**
414 * @tc.name: SchemaMgrTest008
415 * @tc.desc: Cloud schema or local schema are not exist
416 * @tc.type: FUNC
417 * @tc.require:
418 * @tc.author: wanyi
419 */
420 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest008, TestSize.Level0)
421 {
422 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
423 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
424 TableInfo table;
425 table.SetTableName(TABLE_NAME_3);
426 table.AddField(field1);
427 table.AddField(field2);
428 table.SetPrimaryKey(FIELD_NAME_1, 1);
429 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
430
431 TableInfo table2;
432 table2.SetTableName(TABLE_NAME_1);
433 table2.AddField(field1);
434 table2.AddField(field2);
435 table2.SetPrimaryKey(FIELD_NAME_1, 1);
436 table2.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
437
438 RelationalSchemaObject localSchema;
439 localSchema.AddRelationalTable(table);
440 localSchema.AddRelationalTable(table2);
441
442 g_schemaMgr->SetCloudDbSchema(g_schema);
443 // local schema exist but cloud schema not exist
444 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_3, localSchema), -E_SCHEMA_MISMATCH);
445 // cloud schema exist but local schema not exist
446 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_SCHEMA_MISMATCH);
447 // Both cloud schema and local schema does not exist
448 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_4, localSchema), -E_SCHEMA_MISMATCH);
449 // Both cloud schema and local schema exist
450 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_1, localSchema), E_OK);
451
452 g_schemaMgr->SetCloudDbSchema(g_schema2);
453 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_3, localSchema), E_OK);
454 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_1, localSchema), -E_SCHEMA_MISMATCH);
455 }
456
457 /**
458 * @tc.name: SchemaMgrTest008
459 * @tc.desc: Test schema mgr with empty local schema
460 * @tc.type: FUNC
461 * @tc.require:
462 * @tc.author: wanyi
463 */
464 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest009, TestSize.Level0)
465 {
466 RelationalSchemaObject localSchema;
467 g_schemaMgr->SetCloudDbSchema(g_schema);
468 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_1, localSchema), -E_SCHEMA_MISMATCH);
469 }
470
471 /**
472 * @tc.name: SchemaMgrTest010
473 * @tc.desc: Test local schema with un-expected sync type
474 * @tc.type: FUNC
475 * @tc.require:
476 * @tc.author: wanyi
477 */
478 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest010, TestSize.Level0)
479 {
480 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
481 FieldInfo field2 = SetField(FIELD_NAME_2, "int", true);
482 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
483
484 TableInfo table;
485 table.SetTableName(TABLE_NAME_2);
486 table.AddField(field1);
487 table.AddField(field2);
488 table.AddField(field3);
489 table.SetPrimaryKey(FIELD_NAME_1, 1);
490 table.SetTableSyncType(TableSyncType::DEVICE_COOPERATION);
491 RelationalSchemaObject localSchema;
492 localSchema.AddRelationalTable(table);
493
494 g_schemaMgr->SetCloudDbSchema(g_schema);
495 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_NOT_SUPPORT);
496 }
497
498 /**
499 * @tc.name: SchemaMgrTest011
500 * @tc.desc: Test local schema with un-expected data type
501 * @tc.type: FUNC
502 * @tc.require:
503 * @tc.author: wanyi
504 */
505 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest011, TestSize.Level0)
506 {
507 FieldInfo field1 = SetField(FIELD_NAME_1, "int", true);
508 FieldInfo field2 = SetField(FIELD_NAME_2, "text", true);
509 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
510
511 TableInfo table;
512 table.SetTableName(TABLE_NAME_2);
513 table.AddField(field1);
514 table.AddField(field2);
515 table.AddField(field3);
516 table.SetPrimaryKey(FIELD_NAME_1, 1);
517 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
518 RelationalSchemaObject localSchema;
519 localSchema.AddRelationalTable(table);
520
521 g_schemaMgr->SetCloudDbSchema(g_schema);
522 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_2, localSchema), -E_SCHEMA_MISMATCH);
523 }
524
525 /**
526 * @tc.name: SchemaMgrTest012
527 * @tc.desc: table 3 contain primary asset field
528 * @tc.type: FUNC
529 * @tc.require:
530 * @tc.author: wanyi
531 */
532 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest012, TestSize.Level0)
533 {
534 FieldInfo field1 = SetField(FIELD_NAME_1, "blob", true);
535 FieldInfo field2 = SetField(FIELD_NAME_2, "text", true);
536 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
537
538 TableInfo table;
539 table.SetTableName(TABLE_NAME_3);
540 table.AddField(field1);
541 table.AddField(field2);
542 table.AddField(field3);
543 table.SetPrimaryKey(FIELD_NAME_1, 1);
544 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
545 RelationalSchemaObject localSchema;
546 localSchema.AddRelationalTable(table);
547
548 g_schemaMgr->SetCloudDbSchema(g_schema);
549 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_3, localSchema), -E_SCHEMA_MISMATCH);
550 }
551
552 /**
553 * @tc.name: SchemaMgrTest013
554 * @tc.desc: table 4 do not contain primary assets field
555 * @tc.type: FUNC
556 * @tc.require:
557 * @tc.author: wanyi
558 */
559 HWTEST_F(DistributedDBCloudSchemaMgrTest, SchemaMgrTest013, TestSize.Level0)
560 {
561 /**
562 * @tc.steps:step1. local schema's asset field is not primary
563 * @tc.expected: step1. return ok.
564 */
565 FieldInfo field1 = SetField(FIELD_NAME_1, "blob", true);
566 FieldInfo field2 = SetField(FIELD_NAME_2, "text", true);
567 FieldInfo field3 = SetField(FIELD_NAME_3, "int", true);
568
569 TableInfo table;
570 table.SetTableName(TABLE_NAME_4);
571 table.AddField(field1);
572 table.AddField(field2);
573 table.AddField(field3);
574 table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
575 RelationalSchemaObject localSchema;
576 localSchema.AddRelationalTable(table);
577
578 g_schemaMgr->SetCloudDbSchema(g_schema);
579 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_4, localSchema), E_OK);
580 /**
581 * @tc.steps:step2. local schema's asset field is primary
582 * @tc.expected: step2. return E_SCHEMA_MISMATCH.
583 */
584 table.SetPrimaryKey(FIELD_NAME_1, 1);
585 RelationalSchemaObject localSchemaWithAssetPrimary;
586 localSchemaWithAssetPrimary.AddRelationalTable(table);
587 EXPECT_EQ(g_schemaMgr->ChkSchema(TABLE_NAME_4, localSchemaWithAssetPrimary), -E_SCHEMA_MISMATCH);
588 }
589 }