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