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