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 <iostream>
19 #include <string>
20 #include <string_view>
21 
22 #include "../common.h"
23 #include "block_data.h"
24 #include "executor_pool.h"
25 #include "rdb_errno.h"
26 #include "rdb_helper.h"
27 #include "rdb_open_callback.h"
28 #include "shared_block.h"
29 #include "sqlite_shared_result_set.h"
30 #include "step_result_set.h"
31 
32 using namespace testing::ext;
33 using namespace OHOS;
34 using namespace OHOS::NativeRdb;
35 class RdbMultiThreadConnectionTest : public testing::Test {
36 public:
37     static void SetUpTestCase(void);
38     static void TearDownTestCase(void);
39     void SetUp();
40     void TearDown();
41     void GenerateData();
42 
43 protected:
44     class Callback : public RdbOpenCallback {
45     public:
46         int OnCreate(RdbStore &rdbStore) override;
47         int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
48     };
49 
50     static constexpr const char *DATABASE_NAME = "connection_test.db";
51     static constexpr const char *CREATE_TABLE_SQL = "CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name "
52                                                     "TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)";
53     static constexpr int32_t MAX_THREAD = 5;
54     static constexpr int32_t MIN_THREAD = 0;
55 
56     std::shared_ptr<RdbStore> store_;
57     std::shared_ptr<ExecutorPool> executors_;
58 };
59 
OnCreate(RdbStore & rdbStore)60 int RdbMultiThreadConnectionTest::Callback::OnCreate(RdbStore &rdbStore)
61 {
62     return E_OK;
63 }
64 
OnUpgrade(RdbStore & rdbStore,int oldVersion,int newVersion)65 int RdbMultiThreadConnectionTest::Callback::OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion)
66 {
67     return E_OK;
68 }
69 
SetUpTestCase(void)70 void RdbMultiThreadConnectionTest::SetUpTestCase(void)
71 {
72 }
73 
TearDownTestCase(void)74 void RdbMultiThreadConnectionTest::TearDownTestCase(void)
75 {
76 }
77 
SetUp()78 void RdbMultiThreadConnectionTest::SetUp()
79 {
80     executors_ = std::make_shared<ExecutorPool>(MAX_THREAD, MIN_THREAD);
81     store_ = nullptr;
82     RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
83     RdbStoreConfig sqliteSharedRstConfig(RDB_TEST_PATH + DATABASE_NAME);
84     RdbMultiThreadConnectionTest::Callback sqliteSharedRstHelper;
85     int errCode = E_OK;
86     store_ = RdbHelper::GetRdbStore(sqliteSharedRstConfig, 1, sqliteSharedRstHelper, errCode);
87     EXPECT_NE(store_, nullptr);
88 
89     auto ret = store_->ExecuteSql(CREATE_TABLE_SQL);
90     EXPECT_EQ(ret, E_OK);
91     GenerateData();
92 }
93 
TearDown()94 void RdbMultiThreadConnectionTest::TearDown()
95 {
96     executors_ = nullptr;
97     store_ = nullptr;
98     RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
99 }
100 
GenerateData()101 void RdbMultiThreadConnectionTest::GenerateData()
102 {
103     int64_t id;
104     // 0 represent that get first data
105     auto ret = store_->Insert(id, "test", UTUtils::SetRowData(UTUtils::g_rowData[0]));
106     EXPECT_EQ(E_OK, ret);
107     // id is 1
108     EXPECT_EQ(1, id);
109 
110     // 1 represent that get second data
111     ret = store_->Insert(id, "test", UTUtils::SetRowData(UTUtils::g_rowData[1]));
112     EXPECT_EQ(E_OK, ret);
113     // id is 2
114     EXPECT_EQ(2, id);
115 
116     // 2 represent that get third data
117     ret = store_->Insert(id, "test", UTUtils::SetRowData(UTUtils::g_rowData[2]));
118     EXPECT_EQ(E_OK, ret);
119     // id is 3
120     EXPECT_EQ(3, id);
121 }
122 
123 /**
124  * @tc.name: MultiThread_Connection_0001
125  *           if connect is not nullptr when query by calling function querySql while creating table.
126  * @tc.desc: 1.thread 1: query
127  *           2.thread 2: create table
128  * @tc.type: FUNC
129  * @tc.author: leiyanbo
130  */
131 HWTEST_F(RdbMultiThreadConnectionTest, MultiThread_Connection_0001, TestSize.Level2)
132 {
133     std::shared_ptr<BlockData<int32_t>> block1 = std::make_shared<BlockData<int32_t>>(3, false);
__anon0c485b230102() 134     auto taskId1 = executors_->Execute([store = store_, block1]() {
135         constexpr const char *createTable = "CREATE TABLE test";
136         constexpr const char *createTableColumn = " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
137                                                   "name TEXT NOT NULL, age INTEGER, salary REAL, "
138                                                   "blobType BLOB)";
139         int32_t errCode = E_ERROR;
140         for (uint32_t i = 0; i < 2000; i++) {
141             errCode = store->ExecuteSql(createTable + std::to_string(i) + createTableColumn);
142             if (errCode != E_OK) {
143                 break;
144             }
145         }
146         block1->SetValue(errCode);
147     });
148 
149     std::shared_ptr<BlockData<int32_t>> block2 = std::make_shared<BlockData<int32_t>>(3, false);
__anon0c485b230202() 150     auto taskId2 = executors_->Execute([store = store_, block2]() {
151         int32_t errCode = E_ERROR;
152         for (uint32_t i = 0; i < 2000; i++) {
153             auto resultSet = store->QuerySql("SELECT * FROM test");
154             int rowCount = -1;
155             errCode = resultSet->GetRowCount(rowCount);
156             resultSet->Close();
157             if (errCode != E_OK && errCode != E_SQLITE_SCHEMA) {
158                 break;
159             }
160         }
161         auto code = (errCode == E_OK || errCode == E_SQLITE_SCHEMA) ? E_OK : errCode;
162         block2->SetValue(code);
163     });
164 
165     EXPECT_EQ(block1->GetValue(), E_OK);
166     EXPECT_EQ(block2->GetValue(), E_OK);
167     EXPECT_NE(taskId1, taskId2);
168 }
169 
170 /**
171  * @tc.name: MultiThread_Connection_0002
172  *           if connect is not nullptr when query by calling function queryByStep while creating table.
173  * @tc.desc: 1.thread 1: query
174  *           2.thread 2: create table
175  * @tc.type: FUNC
176  * @tc.author: leiyanbo
177  */
178 HWTEST_F(RdbMultiThreadConnectionTest, MultiThread_Connection_0002, TestSize.Level2)
179 {
180     std::shared_ptr<BlockData<int32_t>> block1 = std::make_shared<BlockData<int32_t>>(3, false);
__anon0c485b230302() 181     auto taskId1 = executors_->Execute([store = store_, block1]() {
182         constexpr const char *createTable = "CREATE TABLE test";
183         constexpr const char *createTableColumn = " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
184                                                   "name TEXT NOT NULL, age INTEGER, salary REAL, "
185                                                   "blobType BLOB)";
186         int32_t errCode = E_ERROR;
187         for (uint32_t i = 0; i < 2000; i++) {
188             errCode = store->ExecuteSql(createTable + std::to_string(i) + createTableColumn);
189             if (errCode != E_OK) {
190                 break;
191             }
192         }
193         block1->SetValue(errCode);
194     });
195 
196     std::shared_ptr<BlockData<int32_t>> block2 = std::make_shared<BlockData<int32_t>>(3, false);
__anon0c485b230402() 197     auto taskId2 = executors_->Execute([store = store_, block2]() {
198         int32_t errCode = E_ERROR;
199         for (uint32_t i = 0; i < 2000; i++) {
200             auto resultSet = store->QueryByStep("SELECT * FROM test");
201             int rowCount = -1;
202             errCode = resultSet->GetRowCount(rowCount);
203             resultSet->Close();
204             if (errCode != E_OK && errCode != E_SQLITE_SCHEMA) {
205                 break;
206             }
207         }
208         auto code = (errCode == E_OK || errCode == E_SQLITE_SCHEMA) ? E_OK : errCode;
209         block2->SetValue(code);
210     });
211 
212     EXPECT_EQ(block1->GetValue(), E_OK);
213     EXPECT_EQ(block2->GetValue(), E_OK);
214     EXPECT_NE(taskId1, taskId2);
215 }
216