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 #ifndef DISTRIBUTEDDB_TOOLS_UNIT_TEST_H
17 #define DISTRIBUTEDDB_TOOLS_UNIT_TEST_H
18 
19 #include <algorithm>
20 #include <condition_variable>
21 #include <dirent.h>
22 #include <mutex>
23 #include <string>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <unordered_map>
28 #include <vector>
29 
30 #include "cloud/virtual_cloud_db.h"
31 #include "db_info_handle.h"
32 #include "db_types.h"
33 #include "kv_store_changed_data.h"
34 #include "kv_store_delegate_impl.h"
35 #include "kv_store_delegate_manager.h"
36 #include "kv_store_nb_delegate.h"
37 #include "kv_store_observer.h"
38 #include "kv_store_snapshot_delegate_impl.h"
39 #include "log_print.h"
40 #include "message.h"
41 #include "query.h"
42 #include "relational_store_sqlite_ext.h"
43 #include "store_observer.h"
44 #include "store_changed_data.h"
45 #include "single_ver_kv_entry.h"
46 #include "sqlite_single_ver_natural_store.h"
47 #include "sqlite_utils.h"
48 #include "sync_types.h"
49 #include "store_types.h"
50 #include "types_export.h"
51 
52 namespace DistributedDBUnitTest {
53 struct DatabaseInfo {
54     std::string appId{};
55     std::string userId{};
56     std::string storeId{};
57     std::string dir{};
58     int dbUserVersion = 0;
59 };
60 
61 struct SyncInputArg {
62     uint64_t begin_{};
63     uint64_t end_{};
64     uint32_t blockSize_{};
SyncInputArgSyncInputArg65     SyncInputArg(uint64_t begin, uint64_t end, uint32_t blockSize)
66         : begin_(begin), end_(end), blockSize_(blockSize)
67     {}
68 };
69 
70 struct DataSyncMessageInfo {
71     int messageId_ = DistributedDB::INVALID_MESSAGE_ID;
72     uint16_t messageType_ = DistributedDB::TYPE_INVALID;
73     uint32_t sequenceId_ = 0;
74     uint32_t sessionId_ = 0;
75     int sendCode_ = DistributedDB::E_OK;
76     uint32_t version_ = 0;
77     int32_t mode_ = DistributedDB::PUSH;
78     DistributedDB::WaterMark localMark_ = 0;
79     DistributedDB::WaterMark peerMark_ = 0;
80     DistributedDB::WaterMark deleteMark_ = 0;
81     uint64_t packetId_ = 0;
82 };
83 
84 class DistributedDBToolsUnitTest final {
85 public:
DistributedDBToolsUnitTest()86     DistributedDBToolsUnitTest() {}
~DistributedDBToolsUnitTest()87     ~DistributedDBToolsUnitTest() {}
88 
89     DistributedDBToolsUnitTest(const DistributedDBToolsUnitTest&) = delete;
90     DistributedDBToolsUnitTest& operator=(const DistributedDBToolsUnitTest&) = delete;
91     DistributedDBToolsUnitTest(DistributedDBToolsUnitTest&&) = delete;
92     DistributedDBToolsUnitTest& operator=(DistributedDBToolsUnitTest&&) = delete;
93 
94     // compare whether two vectors are equal.
95     template<typename T>
CompareVector(const std::vector<T> & vec1,const std::vector<T> & vec2)96     static bool CompareVector(const std::vector<T>& vec1, const std::vector<T>& vec2)
97     {
98         if (vec1.size() != vec2.size()) {
99             return false;
100         }
101         for (size_t i = 0; i < vec2.size(); i++) {
102             if (vec1[i] != vec2[i]) {
103                 return false;
104             }
105         }
106         return true;
107     }
108 
109     // compare whether two vectors are equal.
110     template<typename T>
CompareVectorN(const std::vector<T> & vec1,const std::vector<T> & vec2,uint32_t n)111     static bool CompareVectorN(const std::vector<T>& vec1, const std::vector<T>& vec2, uint32_t n)
112     {
113         if (n > std::min(vec1.size(), vec2.size())) {
114             return false;
115         }
116         for (uint32_t i = 0; i < n; i++) {
117             if (vec1[i] != vec2[i]) {
118                 return false;
119             }
120         }
121         return true;
122     }
123     // init the test directory of dir.
124     static void TestDirInit(std::string &dir);
125 
126     // remove the test db files in the test directory of dir.
127     static int RemoveTestDbFiles(const std::string &dir);
128 
129 #ifndef OMIT_MULTI_VER
130     // callback function for get a KvStoreDelegate pointer.
131     static void KvStoreDelegateCallback(DistributedDB::DBStatus, DistributedDB::KvStoreDelegate*,
132         DistributedDB::DBStatus &, DistributedDB::KvStoreDelegate *&);
133 
134     // callback function for get a KvStoreSnapshotDelegate pointer.
135     static void SnapshotDelegateCallback(DistributedDB::DBStatus, DistributedDB::KvStoreSnapshotDelegate*,
136         DistributedDB::DBStatus &, DistributedDB::KvStoreSnapshotDelegate *&);
137 #endif
138 
139     // callback function for get a KvStoreDelegate pointer.
140     static void KvStoreNbDelegateCallback(DistributedDB::DBStatus, DistributedDB::KvStoreNbDelegate*,
141         DistributedDB::DBStatus &, DistributedDB::KvStoreNbDelegate *&);
142 
143     // callback function for get the value.
144     static void ValueCallback(
145         DistributedDB::DBStatus, const DistributedDB::Value &, DistributedDB::DBStatus &, DistributedDB::Value &);
146 
147     // callback function for get an entry vector.
148     static void EntryVectorCallback(DistributedDB::DBStatus, const std::vector<DistributedDB::Entry> &,
149         DistributedDB::DBStatus &, unsigned long &, std::vector<DistributedDB::Entry> &);
150 
151     // sync test helper
152     DistributedDB::DBStatus SyncTest(DistributedDB::KvStoreNbDelegate* delegate,
153         const std::vector<std::string>& devices, DistributedDB::SyncMode mode,
154         std::map<std::string, DistributedDB::DBStatus>& statuses, bool wait = false);
155 
156     // sync test helper
157     DistributedDB::DBStatus SyncTest(DistributedDB::KvStoreNbDelegate* delegate,
158         const std::vector<std::string>& devices, DistributedDB::SyncMode mode,
159         std::map<std::string, DistributedDB::DBStatus>& statuses, const DistributedDB::Query &query);
160 
161     static void GetRandomKeyValue(std::vector<uint8_t> &value, uint32_t defaultSize = 0);
162 
163     static bool IsValueEqual(const DistributedDB::Value &read, const DistributedDB::Value &origin);
164 
165     static bool IsEntryEqual(const DistributedDB::Entry &entryOrg, const DistributedDB::Entry &entryRet);
166 
167     static bool IsEntriesEqual(const std::vector<DistributedDB::Entry> &entriesOrg,
168         const std::vector<DistributedDB::Entry> &entriesRet, bool needSort = false);
169 
170     static bool CheckObserverResult(const std::vector<DistributedDB::Entry> &orgEntries,
171         const std::list<DistributedDB::Entry> &resultLst);
172 
173     static bool IsItemValueExist(const DistributedDB::DataItem &item,
174         const std::vector<DistributedDB::DataItem> &items);
175 
176     static bool IsEntryExist(const DistributedDB::Entry &entry,
177         const std::vector<DistributedDB::Entry> &entries);
178 
179     static bool IsKvEntryExist(const DistributedDB::Entry &entry,
180         const std::vector<DistributedDB::Entry> &entries);
181 
182     static void CalcHash(const std::vector<uint8_t> &value, std::vector<uint8_t> &hashValue);
183 
184     static int CreateMockSingleDb(DatabaseInfo &dbInfo, DistributedDB::OpenDbProperties &properties);
185 
186     static int CreateMockMultiDb(DatabaseInfo &dbInfo, DistributedDB::OpenDbProperties &properties);
187 
188     static int ModifyDatabaseFile(const std::string &fileDir, uint64_t modifyPos = 0,
189         uint32_t modifyCnt = 256, uint32_t value = 0x1F1F1F1F);
190 
191     static int GetSyncDataTest(const SyncInputArg &syncInputArg, DistributedDB::SQLiteSingleVerNaturalStore *store,
192         std::vector<DistributedDB::DataItem> &dataItems, DistributedDB::ContinueToken &continueStmtToken);
193 
194     static int GetSyncDataNextTest(DistributedDB::SQLiteSingleVerNaturalStore *store, uint32_t blockSize,
195         std::vector<DistributedDB::DataItem> &dataItems, DistributedDB::ContinueToken &continueStmtToken);
196 
197     static int PutSyncDataTest(DistributedDB::SQLiteSingleVerNaturalStore *store,
198         const std::vector<DistributedDB::DataItem> &dataItems, const std::string &deviceName);
199 
200     static int PutSyncDataTest(DistributedDB::SQLiteSingleVerNaturalStore *store,
201         const std::vector<DistributedDB::DataItem> &dataItems, const std::string &deviceName,
202         const DistributedDB::QueryObject &query);
203 
204     static int ConvertItemsToSingleVerEntry(const std::vector<DistributedDB::DataItem> &dataItems,
205         std::vector<DistributedDB::SingleVerKvEntry *> &entries);
206 
207     static void ConvertSingleVerEntryToItems(std::vector<DistributedDB::SingleVerKvEntry *> &entries,
208         std::vector<DistributedDB::DataItem> &dataItems);
209 
210     static void ReleaseSingleVerEntry(std::vector<DistributedDB::SingleVerKvEntry *> &entries);
211 
212     static std::vector<uint8_t> GetRandPrefixKey(const std::vector<uint8_t> &prefixKey, uint32_t size);
213 
214     static int GetCurrentDir(std::string& dir);
215 
216     static int GetResourceDir(std::string& dir);
217 
218     static int GetRandInt(const int randMin, const int randMax);
219     static int64_t GetRandInt64(const int64_t randMin, const int64_t randMax);
220 
221     static void PrintTestCaseInfo();
222 
223     static int BuildMessage(const DataSyncMessageInfo &messageInfo, DistributedDB::Message *&message);
224 
225     static void Dump();
226 
227     static std::string GetKvNbStoreDirectory(const std::string &identifier, const std::string &dbFilePath,
228         const std::string &dbDir);
229 
230 private:
231     static int OpenMockMultiDb(DatabaseInfo &dbInfo, DistributedDB::OpenDbProperties &properties);
232 
233     std::mutex syncLock_ {};
234     std::condition_variable syncCondVar_ {};
235 };
236 
237 class KvStoreObserverUnitTest : public DistributedDB::KvStoreObserver {
238 public:
239     KvStoreObserverUnitTest();
240     ~KvStoreObserverUnitTest() override = default;
241 
242     KvStoreObserverUnitTest(const KvStoreObserverUnitTest&) = delete;
243     KvStoreObserverUnitTest& operator=(const KvStoreObserverUnitTest&) = delete;
244     KvStoreObserverUnitTest(KvStoreObserverUnitTest&&) = delete;
245     KvStoreObserverUnitTest& operator=(KvStoreObserverUnitTest&&) = delete;
246 
247     // callback function will be called when the db data is changed.
248     void OnChange(const DistributedDB::KvStoreChangedData&) override;
249 
250     void OnChange(const DistributedDB::StoreChangedData &data) override;
251 
252     void OnChange(DistributedDB::Origin origin, const std::string &originalId,
253         DistributedDB::ChangedData &&data) override;
254 
255     void OnChange(StoreChangedInfo &&data) override;
256 
257     // reset the callCount_ to zero.
258     void ResetToZero();
259 
260     // get callback results.
261     unsigned long GetCallCount() const;
262     const std::list<DistributedDB::Entry> &GetEntriesInserted() const;
263     const std::list<DistributedDB::Entry> &GetEntriesUpdated() const;
264     const std::list<DistributedDB::Entry> &GetEntriesDeleted() const;
265     bool IsCleared() const;
266 private:
267     unsigned long callCount_;
268     bool isCleared_;
269     std::list<DistributedDB::Entry> inserted_;
270     std::list<DistributedDB::Entry> updated_;
271     std::list<DistributedDB::Entry> deleted_;
272 };
273 
274 class RelationalStoreObserverUnitTest : public DistributedDB::StoreObserver {
275 public:
276     RelationalStoreObserverUnitTest();
~RelationalStoreObserverUnitTest()277     ~RelationalStoreObserverUnitTest() {}
278 
279     RelationalStoreObserverUnitTest(const RelationalStoreObserverUnitTest&) = delete;
280     RelationalStoreObserverUnitTest& operator=(const RelationalStoreObserverUnitTest&) = delete;
281     RelationalStoreObserverUnitTest(RelationalStoreObserverUnitTest&&) = delete;
282     RelationalStoreObserverUnitTest& operator=(RelationalStoreObserverUnitTest&&) = delete;
283 
284     // callback function will be called when the db data is changed.
285     void OnChange(const DistributedDB::StoreChangedData &data);
286 
287     void OnChange(DistributedDB::Origin origin, const std::string &originalId, DistributedDB::ChangedData &&data);
288 
289     uint32_t GetCallbackDetailsType() const;
290     void SetCallbackDetailsType(uint32_t type);
291 
292     void SetExpectedResult(const DistributedDB::ChangedData &changedData);
293 
294     bool IsAllChangedDataEq();
295 
296     void ClearChangedData();
297 
298     // reset the callCount_ to zero.
299     void ResetToZero();
300     void ResetCloudSyncToZero();
301 
302     // get callback results.
303     unsigned long GetCallCount() const;
304     unsigned long GetCloudCallCount() const;
305     const std::string GetDataChangeDevice() const;
306     DistributedDB::StoreProperty GetStoreProperty() const;
307 private:
308     unsigned long callCount_;
309     unsigned long cloudCallCount_ = 0;
310     std::string changeDevice_;
311     DistributedDB::StoreProperty storeProperty_;
312     std::unordered_map<std::string, DistributedDB::ChangedData> expectedChangedData_;
313     std::unordered_map<std::string, DistributedDB::ChangedData> savedChangedData_;
314     uint32_t detailsType_ = static_cast<uint32_t>(DistributedDB::CallbackDetailsType::DEFAULT);
315 };
316 
317 class KvStoreCorruptInfo {
318 public:
KvStoreCorruptInfo()319     KvStoreCorruptInfo() {}
~KvStoreCorruptInfo()320     ~KvStoreCorruptInfo() {}
321 
322     KvStoreCorruptInfo(const KvStoreCorruptInfo&) = delete;
323     KvStoreCorruptInfo& operator=(const KvStoreCorruptInfo&) = delete;
324     KvStoreCorruptInfo(KvStoreCorruptInfo&&) = delete;
325     KvStoreCorruptInfo& operator=(KvStoreCorruptInfo&&) = delete;
326 
327     // callback function will be called when the db data is changed.
328     void CorruptCallBack(const std::string &appId, const std::string &userId, const std::string &storeId);
329     size_t GetDatabaseInfoSize() const;
330     bool IsDataBaseCorrupted(const std::string &appId, const std::string &userId, const std::string &storeId) const;
331     void Reset();
332 private:
333     std::vector<DatabaseInfo> databaseInfoVect_;
334 };
335 
336 class RelationalTestUtils {
337 public:
338     static sqlite3 *CreateDataBase(const std::string &dbUri);
339     static int ExecSql(sqlite3 *db, const std::string &sql);
340     static int ExecSql(sqlite3 *db, const std::string &sql, const std::function<int (sqlite3_stmt *)> &bindCallback,
341         const std::function<int (sqlite3_stmt *)> &resultCallback);
342     static void CreateDeviceTable(sqlite3 *db, const std::string &table, const std::string &device);
343     static int CheckSqlResult(sqlite3 *db, const std::string &sql, bool &result);
344     static int CheckTableRecords(sqlite3 *db, const std::string &table);
345     static int GetMetaData(sqlite3 *db, const DistributedDB::Key &key, DistributedDB::Value &value);
346     static int SetMetaData(sqlite3 *db, const DistributedDB::Key &key, const DistributedDB::Value &value);
347     static void CloudBlockSync(const DistributedDB::Query &query, DistributedDB::RelationalStoreDelegate *delegate,
348         DistributedDB::DBStatus expect = DistributedDB::DBStatus::OK,
349         DistributedDB::DBStatus callbackExpect = DistributedDB::DBStatus::OK);
350     static int SelectData(sqlite3 *db, const DistributedDB::TableSchema &schema,
351         std::vector<DistributedDB::VBucket> &data);
352     static DistributedDB::Assets GetAssets(const DistributedDB::Type &value,
353         const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate, bool isAsset = false);
354     static DistributedDB::DBStatus InsertCloudRecord(int64_t begin, int64_t count, const std::string &tableName,
355         const std::shared_ptr<DistributedDB::VirtualCloudDb> &cloudDbPtr, int32_t assetCount = 1);
356     static std::vector<DistributedDB::Assets> GetAllAssets(sqlite3 *db, const DistributedDB::TableSchema &schema,
357         const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate);
358     static int GetRecordLog(sqlite3 *db, const std::string &tableName, std::vector<DistributedDB::VBucket> &records);
359     static int DeleteRecord(sqlite3 *db, const std::string &tableName,
360         const std::vector<std::map<std::string, std::string>> &conditions);
361 };
362 
363 class DBInfoHandleTest : public DistributedDB::DBInfoHandle {
364 public:
365     ~DBInfoHandleTest() override = default;
366 
367     bool IsSupport() override;
368 
369     bool IsNeedAutoSync(const std::string &userId, const std::string &appId, const std::string &storeId,
370         const DistributedDB::DeviceInfos &devInfo) override;
371 
372     void SetLocalIsSupport(bool isSupport);
373 
374     void SetNeedAutoSync(bool needAutoSync);
375 private:
376     std::mutex supportMutex_;
377     bool localIsSupport_ = true;
378     std::mutex autoSyncMutex_;
379     bool isNeedAutoSync_ = true;
380 };
381 } // namespace DistributedDBUnitTest
382 
383 #endif // DISTRIBUTEDDB_TOOLS_UNIT_TEST_H
384