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 
16 #include <gtest/gtest.h>
17 
18 #include "cloud/cloud_db_types.h"
19 #include "db_common.h"
20 #include "db_constant.h"
21 #include "distributeddb_data_generate_unit_test.h"
22 #include "distributeddb_tools_unit_test.h"
23 #include "relational_store_manager.h"
24 
25 using namespace testing::ext;
26 using namespace DistributedDB;
27 using namespace DistributedDBUnitTest;
28 using namespace std;
29 
30 namespace {
31     constexpr const char *DB_SUFFIX = ".db";
32     constexpr const char *STORE_ID = "Relational_Store_ID";
33     std::string g_testDir;
34     std::string g_dbDir;
35     std::string g_storePath;
36     DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
37     RelationalStoreDelegate *g_delegate = nullptr;
38 
39     class DistributedDBCloudInterfacesReferenceTest : public testing::Test {
40     public:
41         static void SetUpTestCase(void);
42         static void TearDownTestCase(void);
43         void SetUp();
44         void TearDown();
45     };
46 
SetUpTestCase(void)47     void DistributedDBCloudInterfacesReferenceTest::SetUpTestCase(void)
48     {
49         DistributedDBToolsUnitTest::TestDirInit(g_testDir);
50         LOGD("Test dir is %s", g_testDir.c_str());
51         g_dbDir = g_testDir + "/";
52         g_storePath = g_dbDir + STORE_ID + DB_SUFFIX;
53         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
54     }
55 
TearDownTestCase(void)56     void DistributedDBCloudInterfacesReferenceTest::TearDownTestCase(void)
57     {
58     }
59 
SetUp(void)60     void DistributedDBCloudInterfacesReferenceTest::SetUp(void)
61     {
62         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
63         ASSERT_NE(db, nullptr);
64         EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
65         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
66 
67         DBStatus status = g_mgr.OpenStore(g_storePath, STORE_ID, {}, g_delegate);
68         EXPECT_EQ(status, OK);
69         ASSERT_NE(g_delegate, nullptr);
70     }
71 
TearDown(void)72     void DistributedDBCloudInterfacesReferenceTest::TearDown(void)
73     {
74         EXPECT_EQ(g_mgr.CloseStore(g_delegate), OK);
75         g_delegate = nullptr;
76         DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir);
77     }
78 
79     /**
80      * @tc.name: SetReferenceTest001
81      * @tc.desc: Test empty args for set reference interface
82      * @tc.type: FUNC
83      * @tc.require:
84      * @tc.author: zhangshjie
85      */
86     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest001, TestSize.Level0)
87     {
88         /**
89          * @tc.steps:step1. call SetReference with empty TableReferenceProperty
90          * @tc.expected: step1. Return INVALID_ARGS.
91          */
92         EXPECT_EQ(g_delegate->SetReference({}), OK);
93         TableReferenceProperty tableReferenceProperty;
94         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
95         std::string sourceTableName = "sourceTable";
96         std::string targetTableName = "targetTable";
97         tableReferenceProperty.sourceTableName = sourceTableName;
98         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
99         tableReferenceProperty.sourceTableName = "";
100         tableReferenceProperty.targetTableName = targetTableName;
101         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
102         tableReferenceProperty.targetTableName = "";
103         std::map<std::string, std::string> columns;
104         columns["col1"] = "col2";
105         tableReferenceProperty.columns = columns;
106         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
107 
108         tableReferenceProperty.sourceTableName = sourceTableName;
109         tableReferenceProperty.targetTableName = targetTableName;
110         tableReferenceProperty.columns = {};
111         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
112         tableReferenceProperty.sourceTableName = "";
113         tableReferenceProperty.targetTableName = targetTableName;
114         tableReferenceProperty.columns = columns;
115         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
116         tableReferenceProperty.sourceTableName = sourceTableName;
117         tableReferenceProperty.targetTableName = "";
118         tableReferenceProperty.columns = columns;
119         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
120     }
121 
122     /**
123      * @tc.name: SetReferenceTest002
124      * @tc.desc: Test set two reference for same two tables
125      * @tc.type: FUNC
126      * @tc.require:
127      * @tc.author: zhangshjie
128      */
129     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest002, TestSize.Level0)
130     {
131         /**
132          * @tc.steps:step1. call SetReference with two TableReferenceProperty which sourceTableName and targetTableName
133          * are both same
134          * @tc.expected: step1. Return INVALID_ARGS.
135          */
136         TableReferenceProperty tableReferenceProperty;
137         std::string sourceTableName = "sourceTable";
138         std::string targetTableName = "targetTable";
139         tableReferenceProperty.sourceTableName = sourceTableName;
140         tableReferenceProperty.targetTableName = targetTableName;
141         std::map<std::string, std::string> columns;
142         columns["col1"] = "col2";
143         tableReferenceProperty.columns = columns;
144         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty, tableReferenceProperty}), INVALID_ARGS);
145 
146         TableReferenceProperty tableReferenceProperty2;
147         tableReferenceProperty2.sourceTableName = "sourceTableName1";
148         tableReferenceProperty2.targetTableName = targetTableName;
149         tableReferenceProperty2.columns = columns;
150         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty, tableReferenceProperty2, tableReferenceProperty}),
151             INVALID_ARGS);
152     }
153 
154     /**
155      * @tc.name: SetReferenceTest003
156      * @tc.desc: Test simple circular dependency
157      * @tc.type: FUNC
158      * @tc.require:
159      * @tc.author: zhangshjie
160      */
161     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest003, TestSize.Level0)
162     {
163         /**
164          * @tc.steps:step1. call SetReference with circular dependency(A->B->A)
165          * @tc.expected: step1. Return INVALID_ARGS.
166          */
167         TableReferenceProperty referenceAB;
168         referenceAB.sourceTableName = "ta";
169         referenceAB.targetTableName = "tb";
170         std::map<std::string, std::string> columns;
171         columns["col1"] = "col2";
172         referenceAB.columns = columns;
173 
174         TableReferenceProperty referenceBA;
175         referenceBA.sourceTableName = "tb";
176         referenceBA.targetTableName = "ta";
177         referenceBA.columns = columns;
178         EXPECT_EQ(g_delegate->SetReference({referenceAB, referenceBA}), INVALID_ARGS);
179 
180         /**
181          * @tc.steps:step2. call SetReference with circular dependency(A->B->C->A)
182          * @tc.expected: step1. Return INVALID_ARGS.
183          */
184         TableReferenceProperty referenceBC;
185         referenceBC.sourceTableName = "tb";
186         referenceBC.targetTableName = "tc";
187         referenceBC.columns = columns;
188 
189         TableReferenceProperty referenceCA;
190         referenceCA.sourceTableName = "tc";
191         referenceCA.targetTableName = "ta";
192         referenceCA.columns = columns;
193 
194         EXPECT_EQ(g_delegate->SetReference({referenceAB, referenceBC, referenceCA}), INVALID_ARGS);
195         EXPECT_EQ(g_delegate->SetReference({referenceCA, referenceAB, referenceBC}), INVALID_ARGS);
196     }
197 
198     /**
199      * @tc.name: SetReferenceTest004
200      * @tc.desc: Test complicated circular dependency
201      * @tc.type: FUNC
202      * @tc.require:
203      * @tc.author: zhangshjie
204      */
205     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest004, TestSize.Level0)
206     {
207         /**
208          * @tc.steps:step1. call SetReference with complicated dependency
209          * @tc.expected: step1. Return INVALID_ARGS.
210          */
211         TableReferenceProperty referenceAB;
212         referenceAB.sourceTableName = "ta";
213         referenceAB.targetTableName = "tb";
214         std::map<std::string, std::string> columns;
215         columns["col1"] = "col2";
216         referenceAB.columns = columns;
217 
218         TableReferenceProperty referenceDE;
219         referenceDE.sourceTableName = "td";
220         referenceDE.targetTableName = "te";
221         referenceDE.columns = columns;
222 
223         TableReferenceProperty referenceAC;
224         referenceAC.sourceTableName = "ta";
225         referenceAC.targetTableName = "tc";
226         referenceAC.columns = columns;
227 
228         TableReferenceProperty referenceEF;
229         referenceEF.sourceTableName = "te";
230         referenceEF.targetTableName = "tf";
231         referenceEF.columns = columns;
232 
233         TableReferenceProperty referenceBD;
234         referenceBD.sourceTableName = "tb";
235         referenceBD.targetTableName = "td";
236         referenceBD.columns = columns;
237 
238         TableReferenceProperty referenceFC;
239         referenceFC.sourceTableName = "tf";
240         referenceFC.targetTableName = "tc";
241         referenceFC.columns = columns;
242 
243         EXPECT_EQ(g_delegate->SetReference({referenceAB, referenceDE, referenceAC, referenceEF, referenceBD,
244             referenceFC}), DISTRIBUTED_SCHEMA_NOT_FOUND);
245 
246         TableReferenceProperty referenceFA;
247         referenceFA.sourceTableName = "tf";
248         referenceFA.targetTableName = "ta";
249         referenceFA.columns = columns;
250         EXPECT_EQ(g_delegate->SetReference(
251             {referenceAB, referenceDE, referenceAC, referenceEF, referenceBD, referenceFC, referenceFA}), INVALID_ARGS);
252     }
253 
254     /**
255      * @tc.name: SetReferenceTest005
256      * @tc.desc: Test table name is case insensitive
257      * @tc.type: FUNC
258      * @tc.require:
259      * @tc.author: zhangshjie
260      */
261     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest005, TestSize.Level0)
262     {
263         /**
264          * @tc.steps:step1. call SetReference with two TableReferenceProperty which sourceTableName and targetTableName
265          * are both same
266          * @tc.expected: step1. Return INVALID_ARGS.
267          */
268         TableReferenceProperty tableReferenceProperty;
269         std::string sourceTableName = "sourceTable";
270         std::string targetTableName = "targetTable";
271         tableReferenceProperty.sourceTableName = sourceTableName;
272         tableReferenceProperty.targetTableName = targetTableName;
273         std::map<std::string, std::string> columns;
274         columns["col1"] = "col2";
275         tableReferenceProperty.columns = columns;
276 
277         TableReferenceProperty tableReferenceProperty2;
278         tableReferenceProperty2.sourceTableName = "SourCeTable";
279         tableReferenceProperty2.targetTableName = "TARGETTABLE";
280         tableReferenceProperty2.columns = columns;
281         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty, tableReferenceProperty2}), INVALID_ARGS);
282     }
283 
284     /**
285      * @tc.name: SetReferenceTest006
286      * @tc.desc: Test reference table doesn't create distributed table
287      * @tc.type: FUNC
288      * @tc.require:
289      * @tc.author: zhangshjie
290      */
291     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest006, TestSize.Level0)
292     {
293         /**
294          * @tc.steps:step1. set reference with table doesn't exists
295          * @tc.expected: step1. Return DISTRIBUTED_SCHEMA_NOT_FOUND.
296          */
297         TableReferenceProperty tableReferenceProperty;
298         std::string sourceTableName = "sourceTable";
299         std::string targetTableName = "targetTable";
300         tableReferenceProperty.sourceTableName = sourceTableName;
301         tableReferenceProperty.targetTableName = targetTableName;
302         std::map<std::string, std::string> columns;
303         columns["col1"] = "col2";
304         tableReferenceProperty.columns = columns;
305         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), DISTRIBUTED_SCHEMA_NOT_FOUND);
306 
307         /**
308          * @tc.steps:step2. set reference with table doesn't create distributed table
309          * @tc.expected: step2. Return DISTRIBUTED_SCHEMA_NOT_FOUND.
310          */
311         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
312         ASSERT_NE(db, nullptr);
313         std::string sql = "create table " + sourceTableName + "(id int);create table " + targetTableName + "(id int);";
314         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
315         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), DISTRIBUTED_SCHEMA_NOT_FOUND);
316 
317         /**
318          * @tc.steps:step3. set reference with one table doesn't create distributed table
319          * @tc.expected: step3. Return DISTRIBUTED_SCHEMA_NOT_FOUND.
320          */
321         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName), OK);
322         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), DISTRIBUTED_SCHEMA_NOT_FOUND);
323         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
324     }
325 
326     /**
327      * @tc.name: SetReferenceTest007
328      * @tc.desc: Test reference table doesn't create cloud sync distributed table
329      * @tc.type: FUNC
330      * @tc.require:
331      * @tc.author: zhangshjie
332      */
333     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest007, TestSize.Level0)
334     {
335         /**
336          * @tc.steps:step1. prepare table and distributed table in device mode
337          * @tc.expected: step1. ok.
338          */
339         std::string sourceTableName = "sourceTable";
340         std::string targetTableName = "targetTable";
341         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
342         ASSERT_NE(db, nullptr);
343         std::string sql = "create table " + sourceTableName + "(id int);create table " + targetTableName + "(id int);";
344         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
345         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName), OK);
346         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName), OK);
347 
348         /**
349          * @tc.steps:step2. set reference with column doesn't exists
350          * @tc.expected: step2. Return INVALID_ARGS.
351          */
352         TableReferenceProperty tableReferenceProperty;
353         tableReferenceProperty.sourceTableName = sourceTableName;
354         tableReferenceProperty.targetTableName = targetTableName;
355         std::map<std::string, std::string> columns;
356         columns["id"] = "id";
357         tableReferenceProperty.columns = columns;
358         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), DISTRIBUTED_SCHEMA_NOT_FOUND);
359 
360         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
361     }
362 
363     /**
364      * @tc.name: SetReferenceTest008
365      * @tc.desc: Test reference col doesn't exists table
366      * @tc.type: FUNC
367      * @tc.require:
368      * @tc.author: zhangshjie
369      */
370     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest008, TestSize.Level0)
371     {
372         /**
373          * @tc.steps:step1. prepare table and distributed table
374          * @tc.expected: step1. ok.
375          */
376         std::string sourceTableName = "sourceTable";
377         std::string targetTableName = "targetTable";
378         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
379         ASSERT_NE(db, nullptr);
380         std::string sql = "create table " + sourceTableName + "(id int);create table " + targetTableName + "(id int);";
381         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
382         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
383         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
384 
385         /**
386          * @tc.steps:step2. set reference with column doesn't exists
387          * @tc.expected: step2. Return INVALID_ARGS.
388          */
389         TableReferenceProperty tableReferenceProperty;
390         tableReferenceProperty.sourceTableName = sourceTableName;
391         tableReferenceProperty.targetTableName = targetTableName;
392         std::map<std::string, std::string> columns;
393         columns["col1"] = "col2";
394         tableReferenceProperty.columns = columns;
395         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), INVALID_ARGS);
396 
397         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
398     }
399 
CheckResult(sqlite3 * db)400     void CheckResult(sqlite3 *db)
401     {
402         int count = 0;
403         std::function<int (sqlite3_stmt *)> bindCallback = [] (sqlite3_stmt *bindStmt) {
404             Key key;
405             DBCommon::StringToVector("relational_schema", key);
406             int errCode = SQLiteUtils::BindBlobToStatement(bindStmt, 1, key, false);
407             return errCode;
408         };
409         std::string sql = "select value from " + DBConstant::RELATIONAL_PREFIX + "metadata where key = ?;";
410         int errCode = RelationalTestUtils::ExecSql(db, sql, bindCallback, [&count] (sqlite3_stmt *stmt) {
411             std::string schemaStr;
412             std::vector<uint8_t> value;
413             EXPECT_EQ(SQLiteUtils::GetColumnBlobValue(stmt, 0, value), E_OK);
414             DBCommon::VectorToString(value, schemaStr);
415             RelationalSchemaObject obj;
416             EXPECT_EQ(obj.ParseFromSchemaString(schemaStr), E_OK);
417             count++;
418             return E_OK;
419         });
420         EXPECT_EQ(errCode, E_OK);
421         EXPECT_EQ(count, 1);
422     }
423 
NormalSetReferenceTest(bool multipleTable)424     void NormalSetReferenceTest(bool multipleTable)
425     {
426         /**
427          * @tc.steps:step1. prepare table and distributed table
428          * @tc.expected: step1. ok.
429          */
430         std::string sourceTableName = "sourceTable";
431         std::string targetTableName = "targetTable";
432         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
433         ASSERT_NE(db, nullptr);
434         std::string sql = "create table " + sourceTableName + "(id int);create table " + targetTableName + "(id int);";
435         if (multipleTable) {
436             sql += "create table t3(key int, value int);create table t4(key int, value int);";
437         }
438         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
439         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
440         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
441         if (multipleTable) {
442             EXPECT_EQ(g_delegate->CreateDistributedTable("t3", DistributedDB::CLOUD_COOPERATION), OK);
443             EXPECT_EQ(g_delegate->CreateDistributedTable("t4", DistributedDB::CLOUD_COOPERATION), OK);
444         }
445 
446         /**
447          * @tc.steps:step2. set reference
448          * @tc.expected: step2. Return OK.
449          */
450         TableReferenceProperty tableReferenceProperty;
451         tableReferenceProperty.sourceTableName = sourceTableName;
452         tableReferenceProperty.targetTableName = targetTableName;
453         std::map<std::string, std::string> columns;
454         columns["id"] = "id";
455         tableReferenceProperty.columns = columns;
456         std::vector<TableReferenceProperty> vec;
457         vec.emplace_back(tableReferenceProperty);
458         if (multipleTable) {
459             TableReferenceProperty reference;
460             reference.sourceTableName = "t3";
461             reference.targetTableName = "t4";
462             reference.columns["key"] = "key";
463             reference.columns["value"] = "value";
464             vec.emplace_back(reference);
465         }
466         EXPECT_EQ(g_delegate->SetReference(vec), OK);
467 
468         /**
469          * @tc.steps:step3. parse schema in db
470          * @tc.expected: step3. Return OK.
471          */
472         CheckResult(db);
473 
474         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
475     }
476 
477     /**
478      * @tc.name: SetReferenceTest009
479      * @tc.desc: Test normal function for SetReference interface with one table
480      * @tc.type: FUNC
481      * @tc.require:
482      * @tc.author: zhangshjie
483      */
484     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest009, TestSize.Level0)
485     {
486         NormalSetReferenceTest(false);
487     }
488 
489     /**
490      * @tc.name: SetReferenceTest010
491      * @tc.desc: Test normal function for SetReference interface with two table
492      * @tc.type: FUNC
493      * @tc.require:
494      * @tc.author: zhangshjie
495      */
496     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest010, TestSize.Level0)
497     {
498         NormalSetReferenceTest(true);
499     }
500 
ReferenceChangeTest(bool isTableEmpty)501     void ReferenceChangeTest(bool isTableEmpty)
502     {
503         /**
504          * @tc.steps:step1. prepare table and distributed table
505          * @tc.expected: step1. ok.
506          */
507         std::string sourceTableName = "sourceTable";
508         std::string targetTableName = "targetTable";
509         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
510         ASSERT_NE(db, nullptr);
511         std::string sql = "create table " + sourceTableName + "(id int, value text);create table " +
512             targetTableName + "(id int, value text);create table t3 (id int, value text);";
513         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
514         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
515         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
516         EXPECT_EQ(g_delegate->CreateDistributedTable("t3", DistributedDB::CLOUD_COOPERATION), OK);
517 
518         if (!isTableEmpty) {
519             sql = "insert into " + sourceTableName + " values(1, 'zhangsan');";
520             EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
521         }
522 
523         /**
524          * @tc.steps:step2. set reference
525          * @tc.expected: step2. Return OK or PROPERTY_CHANGED.
526          */
527         TableReferenceProperty tableReferenceProperty;
528         tableReferenceProperty.sourceTableName = sourceTableName;
529         tableReferenceProperty.targetTableName = targetTableName;
530         std::map<std::string, std::string> columns;
531         columns["id"] = "id";
532         tableReferenceProperty.columns = columns;
533         if (isTableEmpty) {
534             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
535         } else {
536             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
537         }
538 
539         /**
540          * @tc.steps:step3. set reference again with different table reference
541          * @tc.expected: step3. Return OK or PROPERTY_CHANGED.
542          */
543         tableReferenceProperty.targetTableName = "t3";
544         if (isTableEmpty) {
545             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
546         } else {
547             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
548         }
549 
550         /**
551          * @tc.steps:step4. set reference again with different column reference
552          * @tc.expected: step4. Return OK or PROPERTY_CHANGED.
553          */
554         columns["id"] = "value";
555         tableReferenceProperty.columns = columns;
556         if (isTableEmpty) {
557             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
558         } else {
559             EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
560         }
561 
562         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
563     }
564 
565     /**
566      * @tc.name: SetReferenceTest011
567      * @tc.desc: Test table reference change when table is empty
568      * @tc.type: FUNC
569      * @tc.require:
570      * @tc.author: zhangshjie
571      */
572     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest011, TestSize.Level0)
573     {
574         ReferenceChangeTest(true);
575     }
576 
577     /**
578      * @tc.name: SetReferenceTest012
579      * @tc.desc: Test table reference change when table is not empty
580      * @tc.type: FUNC
581      * @tc.require:
582      * @tc.author: zhangshjie
583      */
584     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest012, TestSize.Level0)
585     {
586         ReferenceChangeTest(false);
587     }
588 
589     /**
590      * @tc.name: SetReferenceTest013
591      * @tc.desc: Test table set reference is case insensitive
592      * @tc.type: FUNC
593      * @tc.require:
594      * @tc.author: zhangshjie
595      */
596     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest013, TestSize.Level0)
597     {
598         /**
599          * @tc.steps:step1. prepare table and distributed table
600          * @tc.expected: step1. ok.
601          */
602         std::string sourceTableName = "sourceTable";
603         std::string targetTableName = "targetTable";
604         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
605         ASSERT_NE(db, nullptr);
606         std::string sql = "create table " + sourceTableName + "(id int, value text);create table " +
607             targetTableName + "(id int, value text);";
608         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
609         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
610         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
611         sql = "insert into " + sourceTableName + " values(1, 'zhangsan');";
612         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
613         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
614 
615         /**
616          * @tc.steps:step2. set reference
617          * @tc.expected: step2. Return PROPERTY_CHANGED.
618          */
619         TableReferenceProperty tableReferenceProperty;
620         tableReferenceProperty.sourceTableName = sourceTableName;
621         tableReferenceProperty.targetTableName = targetTableName;
622         std::map<std::string, std::string> columns;
623         columns["id"] = "id";
624         tableReferenceProperty.columns = columns;
625         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
626 
627         /**
628          * @tc.steps:step3. set reference with same table name, but case different
629          * @tc.expected: step3. Return OK.
630          */
631         tableReferenceProperty.sourceTableName = sourceTableName;
632         tableReferenceProperty.targetTableName = "Targettable";
633         tableReferenceProperty.columns = columns;
634         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
635 
636         /**
637          * @tc.steps:step4. set reference with same column name, but case different(value different)
638          * @tc.expected: step4. Return OK.
639          */
640         tableReferenceProperty.sourceTableName = sourceTableName;
641         tableReferenceProperty.targetTableName = targetTableName;
642         columns["id"] = "ID";
643         tableReferenceProperty.columns = columns;
644         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
645 
646         /**
647          * @tc.steps:step5. set reference with same column name, but case different(key different)
648          * @tc.expected: step5. Return OK.
649          */
650         std::map<std::string, std::string> columns2;
651         columns2["ID"] = "ID";
652         tableReferenceProperty.columns = columns2;
653         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
654 
655         /**
656          * @tc.steps:step6. set reference with column size not equal
657          * @tc.expected: step6. Return PROPERTY_CHANGED.
658          */
659         columns2["ID"] = "ID";
660         columns2["value"] = "value";
661         tableReferenceProperty.columns = columns2;
662         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
663     }
664 
665     /**
666     * @tc.name: SetReferenceTest014
667     * @tc.desc: Test table set reference with multi columns
668     * @tc.type: FUNC
669     * @tc.require:
670     * @tc.author: zhangshjie
671     */
672     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest014, TestSize.Level0)
673     {
674         /**
675          * @tc.steps:step1. prepare table and distributed table
676          * @tc.expected: step1. ok.
677          */
678         std::string sourceTableName = "sourceTable";
679         std::string targetTableName = "targetTable";
680         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
681         ASSERT_NE(db, nullptr);
682         std::string sql = "create table " + sourceTableName + "(id int, value text, name text);create table " +
683             targetTableName + "(id int, value text, name text);create table t3 (id int, value text);";
684         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
685         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
686         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
687         EXPECT_EQ(g_delegate->CreateDistributedTable("t3", DistributedDB::CLOUD_COOPERATION), OK);
688         sql = "insert into " + sourceTableName + " values(1, 'zhangsan', 'test');insert into " + targetTableName +
689             " values(2, 'lisi', 'test2');insert into t3 values(3, 'wangwu');";
690         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
691         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
692 
693         /**
694          * @tc.steps:step2. set reference
695          * @tc.expected: step2. Return PROPERTY_CHANGED.
696          */
697         TableReferenceProperty tableReferenceProperty;
698         tableReferenceProperty.sourceTableName = sourceTableName;
699         tableReferenceProperty.targetTableName = targetTableName;
700         std::map<std::string, std::string> columns;
701         columns["id"] = "id";
702         columns["value"] = "value";
703         tableReferenceProperty.columns = columns;
704         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
705 
706         /**
707          * @tc.steps:step3. set reference with multi columns
708          * @tc.expected: step3. Return PROPERTY_CHANGED.
709          */
710         std::map<std::string, std::string> columns2;
711         columns2["id"] = "id";
712         columns2["name"] = "name";
713         tableReferenceProperty.columns = columns2;
714         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
715 
716         /**
717          * @tc.steps:step4. set reference with multi reference property
718          * @tc.expected: step4. Return PROPERTY_CHANGED.
719          */
720         TableReferenceProperty tableReferenceProperty2;
721         tableReferenceProperty2.sourceTableName = sourceTableName;
722         tableReferenceProperty2.targetTableName = "t3";
723         std::map<std::string, std::string> columns3;
724         columns3["id"] = "id";
725         tableReferenceProperty2.columns = columns3;
726         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty, tableReferenceProperty2}), PROPERTY_CHANGED);
727 
728         /**
729          * @tc.steps:step5. set reference with one reference property
730          * @tc.expected: step5. Return PROPERTY_CHANGED.
731          */
732         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
733     }
734 
SetCloudSchema(RelationalStoreDelegate * delegate)735     void SetCloudSchema(RelationalStoreDelegate *delegate)
736     {
737         TableSchema tableSchema;
738         Field field1 = { "id", TYPE_INDEX<int64_t>, true, false };
739         Field field2 = { "value", TYPE_INDEX<std::string>, false, true };
740         Field field3 = { "name", TYPE_INDEX<std::string>, false, true };
741 
742         tableSchema = { "sourceTable", "src_shared", { field1, field2, field3} };
743         DataBaseSchema dbSchema;
744         dbSchema.tables.push_back(tableSchema);
745         tableSchema = { "targetTable", "dst_shared", { field1, field2, field3} };
746         dbSchema.tables.push_back(tableSchema);
747 
748         EXPECT_EQ(delegate->SetCloudDbSchema(dbSchema), OK);
749     }
750 
751     /**
752     * @tc.name: SetReferenceTest015
753     * @tc.desc: Test reference change of shared table
754     * @tc.type: FUNC
755     * @tc.require:
756     * @tc.author: zhangshjie
757     */
758     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest015, TestSize.Level0)
759     {
760         /**
761          * @tc.steps:step1. prepare table and distributed table
762          * @tc.expected: step1. ok.
763          */
764         std::string sourceTableName = "sourceTable";
765         std::string targetTableName = "targetTable";
766         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
767         ASSERT_NE(db, nullptr);
768         std::string sql = "create table " + sourceTableName + "(id int, value text, name text);create table " +
769             targetTableName + "(id int, value text, name text);";
770         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
771         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
772         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
773         TableReferenceProperty tableReferenceProperty;
774         tableReferenceProperty.sourceTableName = sourceTableName;
775         tableReferenceProperty.targetTableName = targetTableName;
776         std::map<std::string, std::string> columns;
777         columns["id"] = "id";
778         columns["value"] = "value";
779         tableReferenceProperty.columns = columns;
780         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
781 
782         /**
783          * @tc.steps:step2. set cloud db schema, insert data into shared table
784          * @tc.expected: step2. ok.
785          */
786         SetCloudSchema(g_delegate);
787         sql = "insert into src_shared values(1, 'zhangsan', 'test', 'aa', 'bb');";
788         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
789         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
790 
791         /**
792          * @tc.steps:step3. clear reference
793          * @tc.expected: step3. return PROPERTY_CHANGED.
794          */
795         EXPECT_EQ(g_delegate->SetReference({}), PROPERTY_CHANGED);
796     }
797 
798     /**
799     * @tc.name: SetReferenceTest016
800     * @tc.desc: Test set reference after some table was dropped
801     * @tc.type: FUNC
802     * @tc.require:
803     * @tc.author: zhangshjie
804     */
805     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest016, TestSize.Level0)
806     {
807         /**
808          * @tc.steps:step1. prepare table and distributed table, then set reference t1->t2
809          * @tc.expected: step1. return ok.
810          */
811         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
812         ASSERT_NE(db, nullptr);
813         std::string sql = "create table t1(id int, value text);create table t2(id int, value text);" \
814             "create table t3(id int, value text);";
815         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
816         EXPECT_EQ(g_delegate->CreateDistributedTable("t1", DistributedDB::CLOUD_COOPERATION), OK);
817         EXPECT_EQ(g_delegate->CreateDistributedTable("t2", DistributedDB::CLOUD_COOPERATION), OK);
818         EXPECT_EQ(g_delegate->CreateDistributedTable("t3", DistributedDB::CLOUD_COOPERATION), OK);
819         TableReferenceProperty tableReferenceProperty;
820         tableReferenceProperty.sourceTableName = "t1";
821         tableReferenceProperty.targetTableName = "t2";
822         std::map<std::string, std::string> columns;
823         columns["id"] = "id";
824         columns["value"] = "value";
825         tableReferenceProperty.columns = columns;
826         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
827 
828         /**
829          * @tc.steps:step2. drop table t1, then reopen store
830          * @tc.expected: step2. return ok.
831          */
832         sql = "drop table t1;";
833         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
834         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
835         EXPECT_EQ(g_mgr.CloseStore(g_delegate), OK);
836         g_delegate = nullptr;
837         EXPECT_EQ(g_mgr.OpenStore(g_storePath, STORE_ID, {}, g_delegate), OK);
838         ASSERT_NE(g_delegate, nullptr);
839 
840         /**
841          * @tc.steps:step3. set reference t2->t1
842          * @tc.expected: step3. return ok.
843          */
844         tableReferenceProperty.sourceTableName = "t2";
845         tableReferenceProperty.targetTableName = "t3";
846         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), OK);
847     }
848 
849     /**
850      * @tc.name: SetReferenceTest017
851      * @tc.desc: Test log table is case insensitive in set reference interface
852      * @tc.type: FUNC
853      * @tc.require:
854      * @tc.author: zhangshjie
855      */
856     HWTEST_F(DistributedDBCloudInterfacesReferenceTest, SetReferenceTest017, TestSize.Level1)
857     {
858         /**
859          * @tc.steps:step1. prepare table and distributed table
860          * @tc.expected: step1. ok.
861          */
862         std::string sourceTableName = "sourceTable";
863         std::string targetTableName = "targetTable";
864         sqlite3 *db = RelationalTestUtils::CreateDataBase(g_storePath);
865         ASSERT_NE(db, nullptr);
866         std::string sql = "create table " + sourceTableName + "(id int, value text);create table " +
867             targetTableName + "(id int, value text);";
868         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
869         EXPECT_EQ(g_delegate->CreateDistributedTable(sourceTableName, DistributedDB::CLOUD_COOPERATION), OK);
870         EXPECT_EQ(g_delegate->CreateDistributedTable(targetTableName, DistributedDB::CLOUD_COOPERATION), OK);
871         sql = "insert into " + sourceTableName + " values(1, 'zhangsan');";
872         EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
873         EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK);
874 
875         /**
876          * @tc.steps:step2. set reference with same table name, but case mismatch
877          * @tc.expected: step2. Return PROPERTY_CHANGED.
878          */
879         TableReferenceProperty tableReferenceProperty;
880         tableReferenceProperty.sourceTableName = "SourceTable";
881         tableReferenceProperty.targetTableName = targetTableName;
882         std::map<std::string, std::string> columns;
883         columns["id"] = "id";
884         tableReferenceProperty.columns = columns;
885         EXPECT_EQ(g_delegate->SetReference({tableReferenceProperty}), PROPERTY_CHANGED);
886     }
887 }
888