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