1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <gtest/gtest.h>
17 
18 #include <string>
19 
20 #include "common.h"
21 #include "rdb_errno.h"
22 #include "rdb_helper.h"
23 #include "rdb_open_callback.h"
24 
25 using namespace testing::ext;
26 using namespace OHOS::NativeRdb;
27 
28 class RdbAttachTest : public testing::Test {
29 public:
30     static void SetUpTestCase(void);
31     static void TearDownTestCase(void);
32     void SetUp();
33     void TearDown();
34     void QueryCheck1(std::shared_ptr<RdbStore> &store) const;
35     void QueryCheck2(std::shared_ptr<RdbStore> &store) const;
36     void DeleteCheck(std::shared_ptr<RdbStore> &store) const;
37     void UpdateCheck(std::shared_ptr<RdbStore> &store) const;
38     void InsertCheck(std::shared_ptr<RdbStore> &store) const;
39 
40     static constexpr const char *MAIN_DATABASE_NAME = "/data/test/main.db";
41     static constexpr const char *ATTACHED_DATABASE_NAME = "/data/test/attached.db";
42     static constexpr const char *ENCRYPT_ATTACHED_DATABASE_NAME = "/data/test/encrypt_attached.db";
43     static constexpr int BUSY_TIMEOUT = 2;
44 };
45 
46 class MainOpenCallback : public RdbOpenCallback {
47 public:
48     int OnCreate(RdbStore &store) override;
49     int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
50     static const std::string CREATE_TABLE_TEST;
51 };
52 
53 std::string const MainOpenCallback::CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test1(id INTEGER PRIMARY KEY "
54                                                         "AUTOINCREMENT, name TEXT NOT NULL)";
55 
OnCreate(RdbStore & store)56 int MainOpenCallback::OnCreate(RdbStore &store)
57 {
58     return store.ExecuteSql(CREATE_TABLE_TEST);
59 }
60 
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)61 int MainOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
62 {
63     return E_OK;
64 }
65 
66 class AttachedOpenCallback : public RdbOpenCallback {
67 public:
68     int OnCreate(RdbStore &store) override;
69     int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
70     static const std::string CREATE_TABLE_TEST;
71 };
72 
73 std::string const AttachedOpenCallback::CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test2(id INTEGER PRIMARY KEY "
74                                                             "AUTOINCREMENT, name TEXT NOT NULL)";
75 
OnCreate(RdbStore & store)76 int AttachedOpenCallback::OnCreate(RdbStore &store)
77 {
78     return store.ExecuteSql(CREATE_TABLE_TEST);
79 }
80 
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)81 int AttachedOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
82 {
83     return E_OK;
84 }
85 
SetUpTestCase(void)86 void RdbAttachTest::SetUpTestCase(void)
87 {
88     RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
89     AttachedOpenCallback attachedHelper;
90     int errCode = E_OK;
91     std::shared_ptr<RdbStore> attachedStore = RdbHelper::GetRdbStore(attachedConfig, 1, attachedHelper, errCode);
92     EXPECT_NE(attachedStore, nullptr);
93 }
94 
TearDownTestCase(void)95 void RdbAttachTest::TearDownTestCase(void)
96 {
97     RdbHelper::DeleteRdbStore(MAIN_DATABASE_NAME);
98     RdbHelper::DeleteRdbStore(ATTACHED_DATABASE_NAME);
99 }
100 
SetUp(void)101 void RdbAttachTest::SetUp(void)
102 {
103 }
104 
TearDown(void)105 void RdbAttachTest::TearDown(void)
106 {
107     RdbHelper::ClearCache();
108 }
109 
110 /**
111  * @tc.name: RdbStore_Attach_001
112  * @tc.desc: test attach, attach is not supported in wal mode
113  * @tc.type: FUNC
114  */
115 HWTEST_F(RdbAttachTest, RdbStore_Attach_001, TestSize.Level1)
116 {
117     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
118     MainOpenCallback helper;
119     int errCode = E_OK;
120     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
121     EXPECT_NE(store, nullptr);
122 
123     int ret = store->ExecuteSql("ATTACH '" + std::string(ATTACHED_DATABASE_NAME) + "' as attached");
124     EXPECT_EQ(ret, E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE);
125 }
126 
127 /**
128  * @tc.name: RdbStore_Attach_002
129  * @tc.desc: test RdbStore attach
130  * @tc.type: FUNC
131  */
132 HWTEST_F(RdbAttachTest, RdbStore_Attach_002, TestSize.Level1)
133 {
134     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
135     config.SetJournalMode(JournalMode::MODE_TRUNCATE);
136     MainOpenCallback helper;
137     int errCode = E_OK;
138     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
139     EXPECT_NE(store, nullptr);
140 
141     int ret = store->ExecuteSql("ATTACH DATABASE '" + std::string(ATTACHED_DATABASE_NAME) + "' as 'attached'");
142     EXPECT_EQ(ret, E_OK);
143 
144     InsertCheck(store);
145 
146     QueryCheck1(store);
147 
148     ret = store->ExecuteSql("DETACH DATABASE 'attached'");
149     EXPECT_EQ(ret, E_OK);
150 
151     QueryCheck2(store);
152 
153     ret = store->ExecuteSql("attach database '" + std::string(ATTACHED_DATABASE_NAME) + "' as 'attached'");
154     EXPECT_EQ(ret, E_OK);
155 
156     ret = store->ExecuteSql("detach database 'attached'");
157     EXPECT_EQ(ret, E_OK);
158 }
159 
160 /**
161  * @tc.name: RdbStore_Attach_003
162  * @tc.desc: Abnormal testCase for Attach
163  * @tc.type: FUNC
164  */
165 HWTEST_F(RdbAttachTest, RdbStore_Attach_003, TestSize.Level2)
166 {
167     const std::string attachedName = "attached";
168     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
169     MainOpenCallback helper;
170     int errCode = E_OK;
171 
172     // journal mode is wal
173     std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
174     EXPECT_NE(nullptr, store1);
175     EXPECT_EQ(E_OK, errCode);
176     RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
177     auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
178     EXPECT_EQ(E_OK, ret.first);
179     EXPECT_EQ(1, ret.second);
180     QueryCheck1(store1);
181     // use the same attachedName to attach again
182     ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
183     EXPECT_EQ(E_ATTACHED_DATABASE_EXIST, ret.first);
184 
185     ret = store1->Detach(attachedName);
186     EXPECT_EQ(E_OK, ret.first);
187     EXPECT_EQ(0, ret.second);
188     QueryCheck2(store1);
189 }
190 
191 /**
192  * @tc.name: RdbStore_Attach_004
193  * @tc.desc: Abnormal testCase for Attach with wrong path
194  * @tc.type: FUNC
195  */
196 HWTEST_F(RdbAttachTest, RdbStore_Attach_004, TestSize.Level2)
197 {
198     const std::string attachedName = "attached";
199     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
200     MainOpenCallback helper;
201     int errCode = E_OK;
202 
203     // journal mode is wal
204     std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
205     EXPECT_NE(nullptr, store1);
206     EXPECT_EQ(E_OK, errCode);
207     RdbStoreConfig attachedConfig("/wrong/path");
208     auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
209     EXPECT_EQ(E_INVALID_FILE_PATH, ret.first);
210 }
211 
212 /**
213  * @tc.name: RdbStore_Attach_005
214  * @tc.desc: Abnormal testCase for Attach encrypted database
215  * @tc.type: FUNC
216  */
217 HWTEST_F(RdbAttachTest, RdbStore_Attach_005, TestSize.Level2)
218 {
219     int errCode = E_OK;
220     AttachedOpenCallback attachedHelper;
221     RdbStoreConfig encryptAttachedConfig(RdbAttachTest::ENCRYPT_ATTACHED_DATABASE_NAME);
222     encryptAttachedConfig.SetEncryptStatus(true);
223     std::shared_ptr<RdbStore> encryptAttachedStore =
224         RdbHelper::GetRdbStore(encryptAttachedConfig, 1, attachedHelper, errCode);
225     EXPECT_NE(encryptAttachedStore, nullptr);
226 
227     encryptAttachedStore = nullptr;
228     const std::string attachedName = "attached";
229     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
230     MainOpenCallback helper;
231 
232     // journal mode is wal
233     std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
234     EXPECT_NE(nullptr, store1);
235     EXPECT_EQ(E_OK, errCode);
236     auto ret = store1->Attach(encryptAttachedConfig, attachedName, BUSY_TIMEOUT);
237     EXPECT_EQ(E_OK, ret.first);
238     EXPECT_EQ(1, ret.second);
239 
240     int64_t id;
241     ValuesBucket values;
242     values.PutInt("id", 1);
243     values.PutString("name", std::string("lisi"));
244     int res = store1->Insert(id, "test2", values);
245     EXPECT_EQ(res, E_OK);
246     EXPECT_EQ(id, 1);
247     QueryCheck1(store1);
248 
249     ret = store1->Detach(attachedName);
250     EXPECT_EQ(E_OK, ret.first);
251     EXPECT_EQ(0, ret.second);
252     QueryCheck2(store1);
253     RdbHelper::DeleteRdbStore(RdbAttachTest::ENCRYPT_ATTACHED_DATABASE_NAME);
254 }
255 
256 /**
257  * @tc.name: RdbStore_Attach_006
258  * @tc.desc: Abnormal testCase for Attach
259  * @tc.type: FUNC
260  */
261 HWTEST_F(RdbAttachTest, RdbStore_Attach_006, TestSize.Level2)
262 {
263     const std::string attachedName = "attached";
264     RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
265     MainOpenCallback helper;
266     int errCode = E_OK;
267 
268     // journal mode is wal
269     std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
270     EXPECT_NE(nullptr, store1);
271     EXPECT_EQ(E_OK, errCode);
272     RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
273     auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
274     EXPECT_EQ(E_OK, ret.first);
275     EXPECT_EQ(1, ret.second);
276 
277     UpdateCheck(store1);
278     DeleteCheck(store1);
279 
280     ret = store1->Detach(attachedName);
281     EXPECT_EQ(E_OK, ret.first);
282     EXPECT_EQ(0, ret.second);
283 }
284 
QueryCheck1(std::shared_ptr<RdbStore> & store) const285 void RdbAttachTest::QueryCheck1(std::shared_ptr<RdbStore> &store) const
286 {
287     std::shared_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1");
288     EXPECT_NE(resultSet, nullptr);
289     int ret = resultSet->GoToNextRow();
290     EXPECT_EQ(ret, E_OK);
291     int columnIndex;
292     int intVal;
293     ret = resultSet->GetColumnIndex("id", columnIndex);
294     EXPECT_EQ(ret, E_OK);
295     ret = resultSet->GetInt(columnIndex, intVal);
296     EXPECT_EQ(ret, E_OK);
297     EXPECT_EQ(intVal, 1);
298     std::string strVal;
299     ret = resultSet->GetColumnIndex("name", columnIndex);
300     EXPECT_EQ(ret, E_OK);
301     ret = resultSet->GetString(columnIndex, strVal);
302     EXPECT_EQ(ret, E_OK);
303     EXPECT_EQ(strVal, "zhangsan");
304 
305     resultSet = store->QuerySql("SELECT * FROM test2");
306     EXPECT_NE(resultSet, nullptr);
307     ret = resultSet->GoToNextRow();
308     EXPECT_EQ(ret, E_OK);
309     ret = resultSet->GetColumnIndex("id", columnIndex);
310     EXPECT_EQ(ret, E_OK);
311     ret = resultSet->GetInt(columnIndex, intVal);
312     EXPECT_EQ(ret, E_OK);
313     EXPECT_EQ(intVal, 1);
314     ret = resultSet->GetColumnIndex("name", columnIndex);
315     EXPECT_EQ(ret, E_OK);
316     ret = resultSet->GetString(columnIndex, strVal);
317     EXPECT_EQ(ret, E_OK);
318     EXPECT_EQ(strVal, "lisi");
319 }
320 
QueryCheck2(std::shared_ptr<RdbStore> & store) const321 void RdbAttachTest::QueryCheck2(std::shared_ptr<RdbStore> &store) const
322 {
323     std::shared_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1");
324     EXPECT_NE(resultSet, nullptr);
325     int ret = resultSet->GoToNextRow();
326     EXPECT_EQ(ret, E_OK);
327     int columnIndex;
328     int intVal;
329     ret = resultSet->GetColumnIndex("id", columnIndex);
330     EXPECT_EQ(ret, E_OK);
331     ret = resultSet->GetInt(columnIndex, intVal);
332     EXPECT_EQ(ret, E_OK);
333     EXPECT_EQ(intVal, 1);
334     std::string strVal;
335     ret = resultSet->GetColumnIndex("name", columnIndex);
336     EXPECT_EQ(ret, E_OK);
337     ret = resultSet->GetString(columnIndex, strVal);
338     EXPECT_EQ(ret, E_OK);
339     EXPECT_EQ(strVal, "zhangsan");
340 
341     // detached, no table test2
342     resultSet = store->QuerySql("SELECT * FROM test2");
343     EXPECT_NE(resultSet, nullptr);
344 }
345 
DeleteCheck(std::shared_ptr<RdbStore> & store) const346 void RdbAttachTest::DeleteCheck(std::shared_ptr<RdbStore> &store) const
347 {
348     int changedRows = 0;
349     AbsRdbPredicates predicates("test1");
350     predicates.EqualTo("id", 1);
351     int ret = store->Delete(changedRows, predicates);
352     EXPECT_EQ(ret, E_OK);
353     EXPECT_EQ(changedRows, 1);
354 
355     std::shared_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1 where name = 'lisi_update1'");
356     EXPECT_NE(resultSet, nullptr);
357     int count = 0;
358     resultSet->GetRowCount(count);
359     EXPECT_EQ(0, count);
360 
361     int changedRows2 = 0;
362     AbsRdbPredicates predicates2("test2");
363     predicates2.EqualTo("id", 1);
364     ret = store->Delete(changedRows2, predicates2);
365     EXPECT_EQ(ret, E_OK);
366     EXPECT_EQ(changedRows2, 1);
367 
368     std::shared_ptr<ResultSet> resultSet2 = store->QuerySql("SELECT * FROM test2 where name = 'lisi_update2'");
369     EXPECT_NE(resultSet2, nullptr);
370     int count2 = 0;
371     resultSet2->GetRowCount(count2);
372     EXPECT_EQ(0, count2);
373 }
374 
UpdateCheck(std::shared_ptr<RdbStore> & store) const375 void RdbAttachTest::UpdateCheck(std::shared_ptr<RdbStore> &store) const
376 {
377     int changedRows = 0;
378     ValuesBucket values;
379     values.PutString("name", std::string("lisi_update1"));
380     AbsRdbPredicates predicates("test1");
381     predicates.EqualTo("id", 1);
382     int ret = store->Update(changedRows, values, predicates);
383     EXPECT_EQ(ret, E_OK);
384     EXPECT_EQ(changedRows, 1);
385 
386     std::shared_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1 where name = 'lisi_update1'");
387     EXPECT_NE(resultSet, nullptr);
388     int count = 0;
389     resultSet->GetRowCount(count);
390     EXPECT_EQ(1, count);
391 
392     values.Clear();
393     values.PutString("name", std::string("lisi_update2"));
394     AbsRdbPredicates predicates2("test2");
395     predicates2.EqualTo("id", 1);
396     int changedRows2 = 0;
397     ret = store->Update(changedRows2, values, predicates2);
398     EXPECT_EQ(ret, E_OK);
399     EXPECT_EQ(changedRows2, 1);
400 
401     std::shared_ptr<ResultSet> resultSet2 = store->QuerySql("SELECT * FROM test2 where name = 'lisi_update2'");
402     EXPECT_NE(resultSet2, nullptr);
403     int count2 = 0;
404     resultSet2->GetRowCount(count2);
405     EXPECT_EQ(1, count2);
406 }
407 
InsertCheck(std::shared_ptr<RdbStore> & store) const408 void RdbAttachTest::InsertCheck(std::shared_ptr<RdbStore> &store) const
409 {
410     int64_t id;
411     ValuesBucket values;
412     values.PutInt("id", 1);
413     values.PutString("name", std::string("zhangsan"));
414     int ret = store->Insert(id, "test1", values);
415     EXPECT_EQ(ret, E_OK);
416     EXPECT_EQ(id, 1);
417 
418     values.Clear();
419     values.PutInt("id", 1);
420     values.PutString("name", std::string("lisi"));
421     ret = store->Insert(id, "test2", values);
422     EXPECT_EQ(ret, E_OK);
423     EXPECT_EQ(id, 1);
424 }
425