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