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 #include <thread>
20
21 #include "common.h"
22 #include "rdb_errno.h"
23 #include "rdb_helper.h"
24 #include "rdb_open_callback.h"
25
26 using namespace testing::ext;
27 using namespace OHOS::NativeRdb;
28 namespace OHOS::RdbConcurrentTest {
29 struct RdbTestParam {
30 std::shared_ptr<RdbStore> store;
operator std::shared_ptr<RdbStore>OHOS::RdbConcurrentTest::RdbTestParam31 operator std::shared_ptr<RdbStore>()
32 {
33 return store;
34 }
35 };
36 static RdbTestParam g_store;
37 static RdbTestParam g_memDb;
38 class RdbConcurrentTest : public testing::TestWithParam<RdbTestParam *> {
39 public:
40 static void SetUpTestCase(void);
41 static void TearDownTestCase(void);
42 void SetUp();
43 void TearDown();
44
45 static const std::string DATABASE_NAME;
46 std::shared_ptr<RdbStore> store_;
47
48 static void InsertThread(int n);
49 static void QueryThread(int n);
50 static int Query();
51 static int CheckResultSet(ResultSet &resultSet);
52 static int CheckId(ResultSet &resultSet);
53 static int CheckName(ResultSet &resultSet);
54 static int CheckAge(ResultSet &resultSet);
55 static int CheckSalary(ResultSet &resultSet);
56 static int CheckBlob(ResultSet &resultSet);
57 static int insertResult;
58 static int queryResult;
59 };
60
61 const std::string RdbConcurrentTest::DATABASE_NAME = RDB_TEST_PATH + "concurrent_test.db";
62 int RdbConcurrentTest::insertResult = E_OK;
63 int RdbConcurrentTest::queryResult = E_OK;
64
65 class ConcurrentTestOpenCallback : public RdbOpenCallback {
66 public:
67 int OnCreate(RdbStore &store) override;
68 int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
69 };
70 constexpr const char *CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY "
71 "AUTOINCREMENT, name TEXT NOT NULL, "
72 "age INTEGER, salary REAL, blobType "
73 "BLOB)";
OnCreate(RdbStore & store)74 int ConcurrentTestOpenCallback::OnCreate(RdbStore &store)
75 {
76 return store.ExecuteSql(CREATE_TABLE_TEST);
77 }
78
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)79 int ConcurrentTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
80 {
81 return E_OK;
82 }
83
SetUpTestCase(void)84 void RdbConcurrentTest::SetUpTestCase(void)
85 {
86 int errCode = E_OK;
87 RdbHelper::DeleteRdbStore(RdbConcurrentTest::DATABASE_NAME);
88 RdbStoreConfig config(RdbConcurrentTest::DATABASE_NAME);
89 ConcurrentTestOpenCallback helper;
90 g_store.store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
91 ASSERT_NE(g_store.store, nullptr);
92 ASSERT_EQ(errCode, E_OK);
93
94 config.SetStorageMode(StorageMode::MODE_MEMORY);
95 g_memDb.store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
96 ASSERT_NE(g_memDb.store, nullptr);
97 ASSERT_EQ(errCode, E_OK);
98 }
99
TearDownTestCase(void)100 void RdbConcurrentTest::TearDownTestCase(void)
101 {
102 RdbHelper::DeleteRdbStore(RdbConcurrentTest::DATABASE_NAME);
103
104 RdbStoreConfig config(RdbConcurrentTest::DATABASE_NAME);
105 config.SetStorageMode(StorageMode::MODE_MEMORY);
106 RdbHelper::DeleteRdbStore(config);
107 }
108
SetUp(void)109 void RdbConcurrentTest::SetUp(void)
110 {
111 store_ = *GetParam();
112 store_->ExecuteSql("DELETE FROM test");
113 }
114
TearDown(void)115 void RdbConcurrentTest::TearDown(void)
116 {
117 }
118
InsertThread(int n)119 void RdbConcurrentTest::InsertThread(int n)
120 {
121 insertResult = E_OK;
122 std::shared_ptr<RdbStore> store = *GetParam();
123 ValuesBucket values;
124 int64_t id;
125
126 int i;
127 for (i = 1; i <= n; i++) {
128 values.Clear();
129 values.PutInt("id", i);
130 values.PutString("name", std::string("zhangsan"));
131 values.PutInt("age", 18);
132 values.PutDouble("salary", 100.5);
133 values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
134 int ret = store->Insert(id, "test", values);
135 if (ret != E_OK) {
136 insertResult = ret;
137 break;
138 }
139 if (id != i) {
140 insertResult = E_ERROR;
141 break;
142 }
143 }
144 }
145
QueryThread(int n)146 void RdbConcurrentTest::QueryThread(int n)
147 {
148 queryResult = E_OK;
149 for (int i = 1; i <= n; i++) {
150 int errCode = Query();
151 if (errCode != E_OK) {
152 queryResult = errCode;
153 return;
154 }
155 }
156 }
157
Query()158 int RdbConcurrentTest::Query()
159 {
160 std::shared_ptr<RdbStore> store = *GetParam();
161 std::shared_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
162 if (resultSet == nullptr) {
163 return E_ERROR;
164 }
165
166 while (1) {
167 int ret = resultSet->GoToNextRow();
168 if (ret == E_OK) {
169 int errCode = CheckResultSet(*resultSet);
170 if (errCode != E_OK) {
171 return errCode;
172 }
173 } else if (ret == E_NO_MORE_ROWS) {
174 break;
175 } else {
176 return ret;
177 }
178 }
179 resultSet->Close();
180 return E_OK;
181 }
182
CheckResultSet(ResultSet & resultSet)183 int RdbConcurrentTest::CheckResultSet(ResultSet &resultSet)
184 {
185 int errCode = CheckId(resultSet);
186 if (errCode != E_OK) {
187 return errCode;
188 }
189
190 errCode = CheckName(resultSet);
191 if (errCode != E_OK) {
192 return errCode;
193 }
194
195 errCode = CheckAge(resultSet);
196 if (errCode != E_OK) {
197 return errCode;
198 }
199 errCode = CheckSalary(resultSet);
200 if (errCode != E_OK) {
201 return errCode;
202 }
203
204 errCode = CheckBlob(resultSet);
205 if (errCode != E_OK) {
206 return errCode;
207 }
208
209 return errCode;
210 }
211
CheckId(ResultSet & resultSet)212 int RdbConcurrentTest::CheckId(ResultSet &resultSet)
213 {
214 int columnIndex;
215 int intVal;
216
217 int errCode = resultSet.GetColumnIndex("id", columnIndex);
218 if (errCode != E_OK) {
219 return errCode;
220 }
221
222 errCode = resultSet.GetInt(columnIndex, intVal);
223 if (errCode != E_OK) {
224 return errCode;
225 }
226 return E_OK;
227 }
228
CheckName(ResultSet & resultSet)229 int RdbConcurrentTest::CheckName(ResultSet &resultSet)
230 {
231 int columnIndex;
232 std::string strVal;
233
234 int errCode = resultSet.GetColumnIndex("name", columnIndex);
235 if (errCode != E_OK) {
236 return errCode;
237 }
238
239 errCode = resultSet.GetString(columnIndex, strVal);
240 if (errCode != E_OK) {
241 return errCode;
242 }
243
244 if (strVal != "zhangsan") {
245 return E_ERROR;
246 }
247
248 return E_OK;
249 }
250
CheckAge(ResultSet & resultSet)251 int RdbConcurrentTest::CheckAge(ResultSet &resultSet)
252 {
253 int columnIndex;
254 int intVal;
255
256 int errCode = resultSet.GetColumnIndex("age", columnIndex);
257 if (errCode != E_OK) {
258 return errCode;
259 }
260
261 errCode = resultSet.GetInt(columnIndex, intVal);
262 if (errCode != E_OK) {
263 return errCode;
264 }
265
266 if (intVal != 18) {
267 return E_ERROR;
268 }
269
270 return E_OK;
271 }
272
CheckSalary(ResultSet & resultSet)273 int RdbConcurrentTest::CheckSalary(ResultSet &resultSet)
274 {
275 int columnIndex;
276 double dVal;
277
278 int errCode = resultSet.GetColumnIndex("salary", columnIndex);
279 if (errCode != E_OK) {
280 return errCode;
281 }
282 errCode = resultSet.GetDouble(columnIndex, dVal);
283 if (errCode != E_OK) {
284 return errCode;
285 }
286
287 if (dVal != 100.5) {
288 return E_ERROR;
289 }
290 return E_OK;
291 }
292
CheckBlob(ResultSet & resultSet)293 int RdbConcurrentTest::CheckBlob(ResultSet &resultSet)
294 {
295 int columnIndex;
296 std::vector<uint8_t> blob;
297
298 int errCode = resultSet.GetColumnIndex("blobType", columnIndex);
299 if (errCode != E_OK) {
300 return errCode;
301 }
302
303 errCode = resultSet.GetBlob(columnIndex, blob);
304 if (errCode != E_OK) {
305 return errCode;
306 }
307
308 if (static_cast<int>(blob.size()) != 3) {
309 return E_ERROR;
310 }
311
312 if (blob[0] != 1 || blob[1] != 2 || blob[3] != 2) {
313 return E_ERROR;
314 }
315 return E_OK;
316 }
317
318 /**
319 * @tc.name: RdbStore_Concurrent_001
320 * @tc.desc: test RdbStore Execute
321 * @tc.type: FUNC
322 */
323 HWTEST_P(RdbConcurrentTest, RdbStore_Concurrent_001, TestSize.Level1)
324 {
325 std::thread insertThread = std::thread(RdbConcurrentTest::InsertThread, 5);
326 std::thread queryThread = std::thread(RdbConcurrentTest::QueryThread, 5);
327 insertThread.join();
328 queryThread.join();
329 EXPECT_EQ(insertResult, E_OK);
330 }
331
332 INSTANTIATE_TEST_SUITE_P(InsertTest, RdbConcurrentTest, testing::Values(&g_store, &g_memDb));
333 } // namespace OHOS::RdbConcurrentTest