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 #include <gtest/gtest.h>
16 #include <gtest/hwext/gtest-multithread.h>
17 #include <sys/types.h>
18
19 #include <chrono>
20 #include <cstdint>
21 #include <future>
22 #include <map>
23 #include <memory>
24 #include <ostream>
25 #include <string>
26 #include <thread>
27
28 #include "../common.h"
29 #include "rdb_errno.h"
30 #include "rdb_helper.h"
31 #include "rdb_open_callback.h"
32 #include "rdb_store.h"
33 #include "rdb_store_impl.h"
34
35 using namespace testing::ext;
36 using namespace testing::mt;
37 using namespace OHOS::NativeRdb;
38
39 class RdbMultiProcessCreateDBTest : public testing::Test {
40 public:
SetUpTestCase()41 static void SetUpTestCase(){};
TearDownTestCase()42 static void TearDownTestCase(){};
SetUp()43 void SetUp(){};
TearDown()44 void TearDown(){};
45 static const std::string databaseName;
46 static const std::string createTabSql;
47 static void Create();
48
49 class Callback : public RdbOpenCallback {
50 public:
51 int OnCreate(RdbStore &rdbStore) override;
52 int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
53 };
54 };
55 const std::string RdbMultiProcessCreateDBTest::databaseName = "multi_process_create_test.db";
56 const std::string RdbMultiProcessCreateDBTest::createTabSql =
57 "CREATE TABLE IF NOT EXISTS test "
58 "(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)";
59
60 static constexpr uint32_t RETRY_COUNT = 2;
61 static constexpr int32_t SLEEP_TIME = 500;
62
OnCreate(RdbStore & store)63 int RdbMultiProcessCreateDBTest::Callback::OnCreate(RdbStore &store)
64 {
65 return store.ExecuteSql(createTabSql);
66 }
67
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)68 int RdbMultiProcessCreateDBTest::Callback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
69 {
70 return E_OK;
71 }
72
CheckAge(std::shared_ptr<ResultSet> & resultSet)73 void CheckAge(std::shared_ptr<ResultSet> &resultSet)
74 {
75 int columnIndex;
76 int intVal;
77 ColumnType columnType;
78 int ret = resultSet->GetColumnIndex("age", columnIndex);
79 EXPECT_EQ(ret, E_OK);
80 ret = resultSet->GetColumnType(columnIndex, columnType);
81 EXPECT_EQ(ret, E_OK);
82 EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER);
83 ret = resultSet->GetInt(columnIndex, intVal);
84 EXPECT_EQ(ret, E_OK);
85 // 18: age is 18
86 EXPECT_EQ(18, intVal);
87 }
88
CheckSalary(std::shared_ptr<ResultSet> & resultSet)89 void CheckSalary(std::shared_ptr<ResultSet> &resultSet)
90 {
91 int columnIndex;
92 double dVal;
93 ColumnType columnType;
94 int ret = resultSet->GetColumnIndex("salary", columnIndex);
95 EXPECT_EQ(ret, E_OK);
96 ret = resultSet->GetColumnType(columnIndex, columnType);
97 EXPECT_EQ(ret, E_OK);
98 EXPECT_EQ(columnType, ColumnType::TYPE_FLOAT);
99 ret = resultSet->GetDouble(columnIndex, dVal);
100 EXPECT_EQ(ret, E_OK);
101 // 100.5: salary is 100.5
102 EXPECT_EQ(100.5, dVal);
103 }
104
CheckBlob(std::shared_ptr<ResultSet> & resultSet)105 void CheckBlob(std::shared_ptr<ResultSet> &resultSet)
106 {
107 int columnIndex;
108 std::vector<uint8_t> blob;
109 ColumnType columnType;
110 int ret = resultSet->GetColumnIndex("blobType", columnIndex);
111 EXPECT_EQ(ret, E_OK);
112 ret = resultSet->GetColumnType(columnIndex, columnType);
113 EXPECT_EQ(ret, E_OK);
114 EXPECT_EQ(columnType, ColumnType::TYPE_BLOB);
115 ret = resultSet->GetBlob(columnIndex, blob);
116 EXPECT_EQ(ret, E_OK);
117 // 3: blob size
118 EXPECT_EQ(3, static_cast<int>(blob.size()));
119 // 1: blob[0] is 1
120 EXPECT_EQ(1, blob[0]);
121 // 2: blob[1] is 2
122 EXPECT_EQ(2, blob[1]);
123 // 3: blob[2] is 3
124 EXPECT_EQ(3, blob[2]);
125 }
126
CheckResultSet(std::shared_ptr<RdbStore> & store)127 void CheckResultSet(std::shared_ptr<RdbStore> &store)
128 {
129 std::shared_ptr<ResultSet> resultSet =
130 store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
131 EXPECT_NE(resultSet, nullptr);
132
133 int columnIndex;
134 int intVal;
135 std::string strVal;
136 ColumnType columnType;
137 int position;
138 int ret = resultSet->GetRowIndex(position);
139 EXPECT_EQ(ret, E_OK);
140 EXPECT_EQ(position, -1);
141
142 ret = resultSet->GetColumnType(0, columnType);
143 EXPECT_EQ(ret, E_ROW_OUT_RANGE);
144
145 ret = resultSet->GoToFirstRow();
146 EXPECT_EQ(ret, E_OK);
147
148 ret = resultSet->GetColumnIndex("id", columnIndex);
149 EXPECT_EQ(ret, E_OK);
150 EXPECT_EQ(columnIndex, 0);
151 ret = resultSet->GetColumnType(columnIndex, columnType);
152 EXPECT_EQ(ret, E_OK);
153 EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER);
154 ret = resultSet->GetInt(columnIndex, intVal);
155 EXPECT_EQ(ret, E_OK);
156 EXPECT_EQ(1, intVal);
157
158 ret = resultSet->GetColumnIndex("name", columnIndex);
159 EXPECT_EQ(ret, E_OK);
160 ret = resultSet->GetColumnType(columnIndex, columnType);
161 EXPECT_EQ(ret, E_OK);
162 EXPECT_EQ(columnType, ColumnType::TYPE_STRING);
163 ret = resultSet->GetString(columnIndex, strVal);
164 EXPECT_EQ(ret, E_OK);
165 EXPECT_EQ("zhangsan", strVal);
166
167 CheckAge(resultSet);
168 CheckSalary(resultSet);
169 CheckBlob(resultSet);
170
171 ret = resultSet->Close();
172 EXPECT_EQ(ret, E_OK);
173 }
174
Create()175 void RdbMultiProcessCreateDBTest::Create()
176 {
177 int errCode = E_OK;
178 RdbStoreConfig config(RDB_TEST_PATH + RdbMultiProcessCreateDBTest::databaseName);
179 config.SetEncryptStatus(true);
180 RdbMultiProcessCreateDBTest::Callback helper;
181 for (uint32_t retry = 0; retry < RETRY_COUNT; ++retry) {
182 auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
183 EXPECT_TRUE(errCode == E_SQLITE_BUSY || errCode == E_OK);
184 if (errCode != E_SQLITE_BUSY) {
185 EXPECT_NE(store, nullptr);
186 break;
187 }
188 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
189 }
190 auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
191 EXPECT_TRUE(errCode == E_SQLITE_BUSY || errCode == E_OK);
192 ASSERT_NE(store, nullptr);
193
194 int64_t id;
195 ValuesBucket values;
196 values.Put("name", "zhangsan");
197 // 18: age is 18
198 values.Put("age", 18);
199 // 100.5: salary is 100.5
200 values.Put("salary", 100.5);
201 values.Put("blobType", std::vector<uint8_t>{ 1, 2, 3 });
202 int ret = store->Insert(id, "test", values);
203 EXPECT_EQ(ret, E_OK);
204
205 CheckResultSet(store);
206 // 2: await 2s
207 std::this_thread::sleep_for(std::chrono::seconds(2));
208 RdbHelper::DeleteRdbStore(RDB_TEST_PATH + RdbMultiProcessCreateDBTest::databaseName);
209 }
210
211 /* *
212 * @tc.name: Rdb_ConcurrentCreate_001
213 * @tc.desc: tow processes create database at the same time
214 * @tc.type: FUNC
215 */
216 HWTEST_F(RdbMultiProcessCreateDBTest, Rdb_ConcurrentCreate_001, TestSize.Level1)
217 {
218 Create();
219 }
220
main(int32_t argc,char * argv[])221 int32_t main(int32_t argc, char *argv[])
222 {
223 testing::GTEST_FLAG(output) = "xml:./";
224 testing::InitGoogleTest(&argc, argv);
225 pid_t pid = fork();
226 if (pid == 0) {
227 RdbMultiProcessCreateDBTest::Create();
228 exit(0);
229 } else if (pid < 0) {
230 return 1;
231 }
232 int res = RUN_ALL_TESTS();
233 if (pid > 0) {
234 int status;
235 waitpid(pid, &status, 0);
236 }
237 return res;
238 }