1 /*
2  * Copyright (c) 2024 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 "cloud_db_types.h"
19 #include "distributeddb_tools_unit_test.h"
20 #include "runtime_config.h"
21 #include "sqlite_relational_utils.h"
22 #include "virtual_cloud_data_translate.h"
23 
24 using namespace testing::ext;
25 using namespace DistributedDB;
26 using namespace DistributedDBUnitTest;
27 
28 namespace {
29     constexpr const char *CREATE_TABLE_SQL =
30         "CREATE TABLE IF NOT EXISTS worker1(" \
31         "id INT PRIMARY KEY,"
32         "name TEXT," \
33         "height REAL ," \
34         "married BOOLEAN ," \
35         "photo BLOB," \
36         "asset BLOB," \
37         "assets BLOB);";
38     const Asset g_localAsset = {
39         .version = 1, .name = "Phone", .assetId = "", .subpath = "/local/sync", .uri = "/local/sync",
40         .modifyTime = "123456", .createTime = "", .size = "256", .hash = "ASE"
41     };
42     std::string g_testDir;
43     std::string g_dbDir;
44     sqlite3 *g_db = nullptr;
45 
46 class DistributedDBSqliteRelationalUtilsTest : public testing::Test {
47 public:
48     static void SetUpTestCase(void);
49     static void TearDownTestCase(void);
50     void SetUp();
51     void TearDown();
52 protected:
53     void CreateUserDBAndTable();
54     void PrepareStatement(const std::string &sql, sqlite3_stmt *&statement, bool hasCloudDataTranslate);
55     std::shared_ptr<VirtualCloudDataTranslate> virtualCloudDataTranslate_ = nullptr;
56 };
57 
SetUpTestCase(void)58 void DistributedDBSqliteRelationalUtilsTest::SetUpTestCase(void)
59 {
60     DistributedDBToolsUnitTest::TestDirInit(g_testDir);
61     LOGI("The test db is:%s", g_testDir.c_str());
62     g_dbDir = g_testDir + "/";
63 }
64 
TearDownTestCase(void)65 void DistributedDBSqliteRelationalUtilsTest::TearDownTestCase(void)
66 {
67 }
68 
SetUp()69 void DistributedDBSqliteRelationalUtilsTest::SetUp()
70 {
71     DistributedDBToolsUnitTest::PrintTestCaseInfo();
72     g_db = RelationalTestUtils::CreateDataBase(g_dbDir + "test.db");
73     CreateUserDBAndTable();
74 }
75 
TearDown()76 void DistributedDBSqliteRelationalUtilsTest::TearDown()
77 {
78     sqlite3_close_v2(g_db);
79     g_db = nullptr;
80     if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
81         LOGE("rm test db files error.");
82     }
83 }
84 
CreateUserDBAndTable()85 void DistributedDBSqliteRelationalUtilsTest::CreateUserDBAndTable()
86 {
87     ASSERT_EQ(RelationalTestUtils::ExecSql(g_db, "PRAGMA journal_mode=WAL;"), SQLITE_OK);
88     ASSERT_EQ(RelationalTestUtils::ExecSql(g_db, CREATE_TABLE_SQL), SQLITE_OK);
89 }
90 
PrepareStatement(const std::string & sql,sqlite3_stmt * & statement,bool hasCloudDataTranslate)91 void DistributedDBSqliteRelationalUtilsTest::PrepareStatement(const std::string &sql, sqlite3_stmt *&statement,
92     bool hasCloudDataTranslate)
93 {
94     ASSERT_EQ(SQLiteUtils::GetStatement(g_db, sql, statement), E_OK);
95     VBucket data;
96     data.insert_or_assign("id", 1L);
97     data.insert_or_assign("name", "lihua");
98     data.insert_or_assign("height", 166.0); // 166.0 is random double value
99     data.insert_or_assign("married", true);
100     std::vector<uint8_t> photo(1, 'v');
101     data.insert_or_assign("photo", photo);
102     data.insert_or_assign("asset", g_localAsset);
103     Assets assets = { g_localAsset };
104     data.insert_or_assign("assets", assets);
105     EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 1, data["id"]), E_OK); // 1 is id cid
106     EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 2, data["name"]), E_OK); // 2 is name cid
107     EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 3, data["height"]), E_OK); // 3 is height cid
108     EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 4, data["married"]), E_OK); // 4 is married cid
109     EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 5, data["photo"]), E_OK); // 5 is photo cid
110     if (hasCloudDataTranslate) {
111         EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 6, data["asset"]), E_OK); // 6 is asset cid
112         EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 7, data["assets"]), E_OK); // 7 is assets cid
113     } else {
114         RuntimeConfig::SetCloudTranslate(nullptr);
115         EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 6, data["asset"]), -E_NOT_INIT); // 6 is asset
116         EXPECT_EQ(SQLiteRelationalUtils::BindStatementByType(statement, 7, data["assets"]), -E_NOT_INIT); // 7 is assets
117     }
118 }
119 
120 /**
121  * @tc.name: SqliteRelationalUtilsTest001
122  * @tc.desc: Test interfaces when statement is nullptr
123  * @tc.type: FUNC
124  * @tc.require:
125  * @tc.author: chenchaohao
126  */
127 HWTEST_F(DistributedDBSqliteRelationalUtilsTest, SqliteRelationalUtilsTest001, TestSize.Level0)
128 {
129     /**
130      * @tc.steps:step1. statement is nullptr
131      * @tc.expected: step1. return OK
132      */
133     sqlite3_stmt *statement = nullptr;
134 
135     /**
136      * @tc.steps:step2. test interface
137      * @tc.expected: step2. return OK
138      */
139     DataValue dataValue;
140     EXPECT_EQ(SQLiteRelationalUtils::GetDataValueByType(statement, 0, dataValue), -E_INVALID_ARGS);
141     Type typeValue;
142     EXPECT_EQ(SQLiteRelationalUtils::GetCloudValueByType(statement, TYPE_INDEX<Nil>, 0, typeValue), -E_INVALID_ARGS);
143     EXPECT_EQ(SQLiteUtils::StepNext(statement, false), -E_INVALID_ARGS);
144     std::string tableName = "worker1";
145     EXPECT_NE(SQLiteRelationalUtils::SelectServerObserver(g_db, tableName, false), E_OK);
146 
147     /**
148      * @tc.steps:step3. close db and test interface
149      * @tc.expected: step3. return OK
150      */
151     sqlite3_close_v2(g_db);
152     g_db = nullptr;
153     std::string fileName = "";
154     EXPECT_FALSE(SQLiteRelationalUtils::GetDbFileName(g_db, fileName));
155     EXPECT_EQ(SQLiteRelationalUtils::SelectServerObserver(g_db, tableName, false), -E_INVALID_ARGS);
156 }
157 
158 /**
159  * @tc.name: SqliteRelationalUtilsTest002
160  * @tc.desc: Test BindStatementByType if dataTranselate is nullptr
161  * @tc.type: FUNC
162  * @tc.require:
163  * @tc.author: chenchaohao
164  */
165 HWTEST_F(DistributedDBSqliteRelationalUtilsTest, SqliteRelationalUtilsTest002, TestSize.Level0)
166 {
167     /**
168      * @tc.steps:step1. prepare sql and bind statement
169      * @tc.expected: step1. return OK
170      */
171     std::string sql = "INSERT OR REPLACE INTO worker1(id, name, height, married, photo, asset, assets)" \
172         "VALUES (?,?,?,?,?,?,?);";
173     sqlite3_stmt *statement = nullptr;
174     PrepareStatement(sql, statement, false);
175     int errCode = E_OK;
176     SQLiteUtils::ResetStatement(statement, true, errCode);
177     ASSERT_EQ(statement, nullptr);
178 }
179 
180 /**
181  * @tc.name: SqliteRelationalUtilsTest003
182  * @tc.desc: Test GetSelectVBucket
183  * @tc.type: FUNC
184  * @tc.require:
185  * @tc.author: chenchaohao
186  */
187 HWTEST_F(DistributedDBSqliteRelationalUtilsTest, SqliteRelationalUtilsTest003, TestSize.Level0)
188 {
189     /**
190      * @tc.steps:step1. set CloudDataTranslate
191      * @tc.expected: step1. return OK
192      */
193     virtualCloudDataTranslate_ = std::make_shared<VirtualCloudDataTranslate>();
194     RuntimeConfig::SetCloudTranslate(virtualCloudDataTranslate_);
195 
196     /**
197      * @tc.steps:step2. insert data
198      * @tc.expected: step2. return OK
199      */
200     std::string sql = "INSERT OR REPLACE INTO worker1(id, name, height, married, photo, asset, assets)" \
201         "VALUES (?,?,?,?,?,?,?);";
202     sqlite3_stmt *statement = nullptr;
203     PrepareStatement(sql, statement, true);
204     EXPECT_EQ(SQLiteUtils::StepWithRetry(statement), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
205     int errCode = E_OK;
206     SQLiteUtils::ResetStatement(statement, true, errCode);
207     ASSERT_EQ(statement, nullptr);
208 
209     /**
210      * @tc.steps:step3. test GetSelectVBucket
211      * @tc.expected: step3. return OK
212      */
213     VBucket data;
214     ASSERT_EQ(SQLiteRelationalUtils::GetSelectVBucket(statement, data), -E_INVALID_ARGS);
215     sql = "SELECT id, name, height, married, photo, asset, assets from worker1;";
216     ASSERT_EQ(SQLiteUtils::GetStatement(g_db, sql, statement), E_OK);
217     EXPECT_EQ(SQLiteRelationalUtils::GetSelectVBucket(statement, data), E_OK);
218     SQLiteUtils::ResetStatement(statement, true, errCode);
219     ASSERT_EQ(statement, nullptr);
220 }
221 }