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 #include <gtest/gtest.h>
17
18 #include "distributeddb_data_generate_unit_test.h"
19 #include "kvdb_manager.h"
20 #include "native_sqlite.h"
21 #include "sqlite_local_kvdb.h"
22 #include "sqlite_local_kvdb_connection.h"
23
24 using namespace testing::ext;
25 using namespace DistributedDB;
26 using namespace DistributedDBUnitTest;
27 using namespace std;
28
29 namespace {
30 string g_testDir;
31 SQLiteLocalKvDBConnection *g_connection = nullptr;
32 SQLiteLocalKvDB *g_invalidDb = nullptr;
33 SQLiteLocalKvDBConnection *g_invalidConnection = nullptr;
34
CreateConnInInvalidDb()35 void CreateConnInInvalidDb()
36 {
37 ASSERT_EQ(g_invalidDb, nullptr);
38 g_invalidConnection = new (std::nothrow) SQLiteLocalKvDBConnection(g_invalidDb);
39 ASSERT_NE(g_invalidConnection, nullptr);
40 }
41
CloseConnInInvalidDb()42 void CloseConnInInvalidDb()
43 {
44 if (g_invalidConnection != nullptr) {
45 delete g_invalidConnection;
46 g_invalidConnection = nullptr;
47 }
48 }
49
CreateConnInNewDb()50 void CreateConnInNewDb()
51 {
52 g_invalidDb = new (std::nothrow) SQLiteLocalKvDB();
53 ASSERT_NE(g_invalidDb, nullptr);
54 int errCode;
55 g_invalidConnection = static_cast<SQLiteLocalKvDBConnection *>(g_invalidDb->GetDBConnection(errCode));
56 ASSERT_NE(g_invalidConnection, nullptr);
57 RefObject::DecObjRef(g_invalidDb);
58 }
59
CloseConnInNewDb()60 void CloseConnInNewDb()
61 {
62 if (g_invalidConnection != nullptr) {
63 EXPECT_EQ(g_invalidConnection->Close(), E_OK);
64 g_invalidConnection = nullptr;
65 g_invalidDb = nullptr;
66 }
67 if (g_invalidDb != nullptr) {
68 delete g_invalidDb;
69 g_invalidDb = nullptr;
70 }
71 }
72
TestFunc(const KvDBCommitNotifyData & data)73 void TestFunc(const KvDBCommitNotifyData &data)
74 {
75 }
76 }
77
78 class DistributedDBStorageDataConnectionTest : public testing::Test {
79 public:
80 static void SetUpTestCase(void);
81 static void TearDownTestCase(void);
82 void SetUp();
83 void TearDown();
84 };
85
SetUpTestCase(void)86 void DistributedDBStorageDataConnectionTest::SetUpTestCase(void)
87 {
88 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
89 }
90
TearDownTestCase(void)91 void DistributedDBStorageDataConnectionTest::TearDownTestCase(void)
92 {
93 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
94 LOGE("rm test db files error!");
95 }
96 }
97
SetUp(void)98 void DistributedDBStorageDataConnectionTest::SetUp(void)
99 {
100 DistributedDBToolsUnitTest::PrintTestCaseInfo();
101 KvDBProperties properties;
102 properties.SetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
103 properties.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
104 properties.SetStringProp(KvDBProperties::DATA_DIR, g_testDir);
105 properties.SetStringProp(KvDBProperties::STORE_ID, "test");
106 properties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, "test");
107
108 int errCode = E_OK;
109 g_connection = static_cast<SQLiteLocalKvDBConnection *>(KvDBManager::GetDatabaseConnection(properties, errCode));
110 EXPECT_EQ(errCode, E_OK);
111 ASSERT_NE(g_connection, nullptr);
112 }
113
TearDown(void)114 void DistributedDBStorageDataConnectionTest::TearDown(void)
115 {
116 if (g_connection != nullptr) {
117 g_connection->Close();
118 g_connection = nullptr;
119 }
120 CloseConnInInvalidDb();
121 CloseConnInNewDb();
122 return;
123 }
124
125 /**
126 * @tc.name: ConnectionTest001
127 * @tc.desc: Get value from abnormal connection
128 * @tc.type: FUNC
129 * @tc.require:
130 * @tc.author: bty
131 */
132 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest001, TestSize.Level1)
133 {
134 /**
135 * @tc.steps: step1. Create a connection when the db is null
136 * @tc.expected: step1. Expect not null
137 */
138 CreateConnInInvalidDb();
139
140 /**
141 * @tc.steps: step2 Get value
142 * @tc.expected: step2. Expect -E_INVALID_DB
143 */
144 IOption option;
145 Value value;
146 EXPECT_EQ(g_invalidConnection->Get(option, KEY_3, value), -E_INVALID_DB);
147 CloseConnInInvalidDb();
148
149 /**
150 * @tc.steps: step3. Use db to create a new connection, but db is not open
151 * @tc.expected: step3. Expect not null
152 */
153 CreateConnInNewDb();
154
155 /**
156 * @tc.steps: step4. Get value
157 * @tc.expected: step4. Expect -E_INVALID_DB
158 */
159 EXPECT_EQ(g_invalidConnection->Get(option, KEY_3, value), -E_INVALID_DB);
160 CloseConnInNewDb();
161 }
162
163 /**
164 * @tc.name: ConnectionTest002
165 * @tc.desc: Delete and clear from abnormal connection
166 * @tc.type: FUNC
167 * @tc.require:
168 * @tc.author: bty
169 */
170 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest002, TestSize.Level1)
171 {
172 /**
173 * @tc.steps: step1. Use db to create a new connection, but db is not open
174 * @tc.expected: step1. Expect not null
175 */
176 CreateConnInNewDb();
177
178 /**
179 * @tc.steps: step2. Clear and delete
180 * @tc.expected: step2. Expect -E_INVALID_DB
181 */
182 IOption option;
183 Value value;
184 EXPECT_EQ(g_invalidConnection->Delete(option, KEY_3), -E_INVALID_DB);
185 EXPECT_EQ(g_invalidConnection->Clear(option), -E_INVALID_DB);
186 CloseConnInNewDb();
187 }
188
189 /**
190 * @tc.name: ConnectionTest003
191 * @tc.desc: Get entries from abnormal connection
192 * @tc.type: FUNC
193 * @tc.require:
194 * @tc.author: bty
195 */
196 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest003, TestSize.Level1)
197 {
198 /**
199 * @tc.steps: step1. Create a connection when the db is null
200 * @tc.expected: step1. Expect not null
201 */
202 CreateConnInInvalidDb();
203
204 /**
205 * @tc.steps: step2. Get entries
206 * @tc.expected: step2. Expect -E_INVALID_DB
207 */
208 IOption option;
209 std::vector<Entry> entry;
210 Key key(DBConstant::MAX_KEY_SIZE + 1, 'w');
211 EXPECT_EQ(g_invalidConnection->GetEntries(option, key, entry), -E_INVALID_DB);
212 CloseConnInInvalidDb();
213
214 /**
215 * @tc.steps: step3. Key is over size
216 * @tc.expected: step3. Expect -E_INVALID_ARGS
217 */
218 CreateConnInNewDb();
219 EXPECT_EQ(g_invalidConnection->GetEntries(option, key, entry), -E_INVALID_ARGS);
220
221 /**
222 * @tc.steps: step4. Key is normal, but the db not open
223 * @tc.expected: step4. Expect -E_INVALID_DB
224 */
225 EXPECT_EQ(g_invalidConnection->GetEntries(option, KEY_3, entry), -E_INVALID_DB);
226 CloseConnInNewDb();
227 }
228
229 /**
230 * @tc.name: ConnectionTest004
231 * @tc.desc: Put batch from abnormal connection
232 * @tc.type: FUNC
233 * @tc.require:
234 * @tc.author: bty
235 */
236 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest004, TestSize.Level1)
237 {
238 /**
239 * @tc.steps: step1. Create a connection when the db is null
240 * @tc.expected: step1. Expect not null
241 */
242 CreateConnInInvalidDb();
243
244 /**
245 * @tc.steps: step2. Put empty entries
246 * @tc.expected: step2. Expect -E_INVALID_ARGS
247 */
248 IOption option;
249 std::vector<Entry> entry;
250 EXPECT_EQ(g_invalidConnection->PutBatch(option, entry), -E_INVALID_ARGS);
251
252 /**
253 * @tc.steps: step3. Entries is normal, but the db is null
254 * @tc.expected: step3. Expect -E_INVALID_ARGS
255 */
256 Value value;
257 Entry ent = {KEY_3, value};
258 entry.push_back(ent);
259 EXPECT_EQ(g_invalidConnection->PutBatch(option, entry), -E_INVALID_ARGS);
260 CloseConnInInvalidDb();
261
262 /**
263 * @tc.steps: step4. The db is not open
264 * @tc.expected: step4. Expect -E_INVALID_DB
265 */
266 CreateConnInNewDb();
267 EXPECT_EQ(g_invalidConnection->PutBatch(option, entry), -E_INVALID_DB);
268 CloseConnInNewDb();
269 }
270
271 /**
272 * @tc.name: ConnectionTest005
273 * @tc.desc: Delete batch from abnormal connection
274 * @tc.type: FUNC
275 * @tc.require:
276 * @tc.author: bty
277 */
278 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest005, TestSize.Level1)
279 {
280 /**
281 * @tc.steps: step1. Create a connection when the db is null
282 * @tc.expected: step1. Expect not null
283 */
284 CreateConnInInvalidDb();
285
286 /**
287 * @tc.steps: step2. delete, but the keys is empty
288 * @tc.expected: step2. Expect -E_INVALID_ARGS
289 */
290 IOption option;
291 std::vector<Key> keys;
292 EXPECT_EQ(g_invalidConnection->DeleteBatch(option, keys), -E_INVALID_ARGS);
293
294 /**
295 * @tc.steps: step3. The key is over size
296 * @tc.expected: step3. Expect -E_INVALID_ARGS
297 */
298 Key key(DBConstant::MAX_KEY_SIZE + 1, 'w');
299 keys.push_back(key);
300 EXPECT_EQ(g_invalidConnection->DeleteBatch(option, keys), -E_INVALID_ARGS);
301
302 /**
303 * @tc.steps: step4. key is normal , but the db is null
304 * @tc.expected: step4. Expect -E_INVALID_DB
305 */
306 keys.clear();
307 keys.push_back(KEY_3);
308 EXPECT_EQ(g_invalidConnection->DeleteBatch(option, keys), -E_INVALID_DB);
309 CloseConnInInvalidDb();
310 }
311
312 /**
313 * @tc.name: ConnectionTest006
314 * @tc.desc: Get snapshot from abnormal connection
315 * @tc.type: FUNC
316 * @tc.require:
317 * @tc.author: bty
318 */
319 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest006, TestSize.Level1)
320 {
321 /**
322 * @tc.steps: step1. Create a connection when the db is null
323 * @tc.expected: step1. Expect not null
324 */
325 CreateConnInInvalidDb();
326
327 /**
328 * @tc.steps: step2. the db is null
329 * @tc.expected: step2. Expect -E_INVALID_DB
330 */
331 IKvDBSnapshot *snapshot = nullptr;
332 EXPECT_EQ(g_invalidConnection->GetSnapshot(snapshot), -E_INVALID_DB);
333 CloseConnInInvalidDb();
334
335 /**
336 * @tc.steps: step3. GetSnapshot after changing db operate perm to DISABLE_PERM
337 * @tc.expected: step3. Expect -E_STALE
338 */
339 SQLiteLocalKvDB *localKvdb = new (std::nothrow) SQLiteLocalKvDB();
340 ASSERT_NE(localKvdb, nullptr);
341 EXPECT_EQ(localKvdb->TryToDisableConnection(OperatePerm::DISABLE_PERM), E_OK);
342 int errCode;
343 SQLiteLocalKvDBConnection *connection =
344 static_cast<SQLiteLocalKvDBConnection *>(localKvdb->NewConnection(errCode));
345 ASSERT_NE(connection, nullptr);
346 EXPECT_EQ(connection->GetSnapshot(snapshot), -E_STALE);
347 EXPECT_EQ(connection->Close(), E_OK);
348 connection = nullptr;
349 localKvdb = nullptr;
350
351 /**
352 * @tc.steps: step4. Get snapshot from normal db, then preClose
353 * @tc.expected: step4. Expect -E_BUSY
354 */
355 EXPECT_EQ(g_connection->GetSnapshot(snapshot), E_OK);
356 EXPECT_EQ(g_connection->PreClose(), -E_BUSY);
357 g_connection->ReleaseSnapshot(snapshot);
358 }
359
360 /**
361 * @tc.name: ConnectionTest007
362 * @tc.desc: Test transaction from abnormal connection
363 * @tc.type: FUNC
364 * @tc.require:
365 * @tc.author: bty
366 */
367 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest007, TestSize.Level1)
368 {
369 /**
370 * @tc.steps: step1. Start transaction when the db is null
371 * @tc.expected: step1. Expect -E_INVALID_DB
372 */
373 CreateConnInInvalidDb();
374 EXPECT_EQ(g_invalidConnection->StartTransaction(), -E_INVALID_DB);
375 CloseConnInInvalidDb();
376
377 /**
378 * @tc.steps: step2. Start transaction and rollback
379 * @tc.expected: step2. Expect true after StartTransaction, false after rollback
380 */
381 g_connection->StartTransaction();
382 EXPECT_EQ(g_connection->IsTransactionStarted(), true);
383 g_connection->RollBack();
384 EXPECT_EQ(g_connection->IsTransactionStarted(), false);
385 }
386
387 /**
388 * @tc.name: ConnectionTest008
389 * @tc.desc: Export,import and rekey from abnormal connection
390 * @tc.type: FUNC
391 * @tc.require:
392 * @tc.author: bty
393 */
394 HWTEST_F(DistributedDBStorageDataConnectionTest, ConnectionTest008, TestSize.Level1)
395 {
396 /**
397 * @tc.steps: step1. the db is null
398 * @tc.expected: step1. Expect -E_INVALID_DB
399 */
400 CreateConnInInvalidDb();
401 CipherPassword passwd;
402 string filePath = g_testDir + "/ExportTest.db";
403 EXPECT_EQ(g_invalidConnection->Rekey(passwd), -E_INVALID_DB);
404 EXPECT_EQ(g_invalidConnection->Export(filePath, passwd), -E_INVALID_DB);
405 EXPECT_EQ(g_invalidConnection->Import(filePath, passwd), -E_INVALID_DB);
406 CloseConnInInvalidDb();
407
408 /**
409 * @tc.steps: step2. Make OperatePerm not equal to NORMAL_PERM
410 * @tc.expected: step2. Expect -E_BUSY
411 */
412 SQLiteLocalKvDB *localKvdb = new (std::nothrow) SQLiteLocalKvDB();
413 ASSERT_NE(localKvdb, nullptr);
414 EXPECT_EQ(localKvdb->TryToDisableConnection(OperatePerm::DISABLE_PERM), E_OK);
415 int errCode;
416 SQLiteLocalKvDBConnection *connection =
417 static_cast<SQLiteLocalKvDBConnection *>(localKvdb->NewConnection(errCode));
418 ASSERT_NE(connection, nullptr);
419 EXPECT_EQ(connection->Import(filePath, passwd), -E_BUSY);
420 EXPECT_EQ(connection->Close(), E_OK);
421 connection = nullptr;
422 localKvdb = nullptr;
423
424 /**
425 * @tc.steps: step3. Test in transaction
426 * @tc.expected: step3. Expect -E_BUSY
427 */
428 g_connection->StartTransaction();
429 EXPECT_EQ(g_connection->Rekey(passwd), -E_BUSY);
430 EXPECT_EQ(g_connection->Import(filePath, passwd), -E_BUSY);
431 g_connection->RollBack();
432
433 /**
434 * @tc.steps: step4. Test after Registering observer
435 * @tc.expected: step4. Expect -E_BUSY
436 */
437 int result;
438 Key key;
439 key.push_back('a');
440 KvDBObserverHandle* handle = g_connection->RegisterObserver(
441 static_cast<unsigned int>(SQLITE_GENERAL_NS_LOCAL_PUT_EVENT), key, TestFunc, result);
442 EXPECT_EQ(result, E_OK);
443 EXPECT_NE(handle, nullptr);
444 EXPECT_EQ(g_connection->Rekey(passwd), -E_BUSY);
445 EXPECT_EQ(g_connection->Import(filePath, passwd), -E_BUSY);
446 g_connection->UnRegisterObserver(handle);
447 }