1 /*
2 * Copyright (c) 2023 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 <random>
19 #include <string>
20
21 #include "common.h"
22 #include "rdb_errno.h"
23 #include "rdb_helper.h"
24 #include "rdb_open_callback.h"
25 #include "sqlite_global_config.h"
26
27 using namespace testing::ext;
28 using namespace OHOS::NativeRdb;
29
30 class RdbWalLimitTest : public testing::Test {
31 public:
32 static void SetUpTestCase(void);
33 static void TearDownTestCase(void);
34 void SetUp();
35 void TearDown();
36
37 static std::vector<uint8_t> CreateRandomData(int32_t len);
38 static void MakeWalReachLimit();
39 static void MakeWalNoReachLimit();
40 static void MakeWalIncrease();
41 static void KeepReadConnection();
42 static ValuesBucket MakeValueBucket(const int &id);
43
44 static const std::string DATABASE_NAME;
45 static std::shared_ptr<RdbStore> store;
46 static std::shared_ptr<ResultSet> resultSet;
47 };
48
49 const std::string RdbWalLimitTest::DATABASE_NAME = RDB_TEST_PATH + "walLimit_test.db";
50 std::shared_ptr<RdbStore> RdbWalLimitTest::store = nullptr;
51 std::shared_ptr<ResultSet> RdbWalLimitTest::resultSet = nullptr;
52
53 // create 1M data
54 std::vector<uint8_t> blobValue = RdbWalLimitTest::CreateRandomData(1 * 1024 * 1024);
55
56 class RdbWalLimitCallback : public RdbOpenCallback {
57 public:
58 int OnCreate(RdbStore &store) override;
59 int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
60 static const std::string CREATE_TABLE_TEST;
61 };
62
63 const std::string RdbWalLimitCallback::CREATE_TABLE_TEST(
64 "CREATE TABLE IF NOT EXISTS test "
65 "(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)");
66
OnCreate(RdbStore & store)67 int RdbWalLimitCallback::OnCreate(RdbStore &store)
68 {
69 return store.ExecuteSql(CREATE_TABLE_TEST);
70 }
71
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)72 int RdbWalLimitCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
73 {
74 return E_OK;
75 }
76
SetUpTestCase(void)77 void RdbWalLimitTest::SetUpTestCase(void)
78 {
79 }
80
TearDownTestCase(void)81 void RdbWalLimitTest::TearDownTestCase(void)
82 {
83 }
84
SetUp(void)85 void RdbWalLimitTest::SetUp(void)
86 {
87 int errCode = E_OK;
88 RdbHelper::DeleteRdbStore(DATABASE_NAME);
89 RdbStoreConfig config(DATABASE_NAME);
90 RdbWalLimitCallback helper;
91 store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
92 EXPECT_NE(store, nullptr);
93 EXPECT_EQ(errCode, E_OK);
94 }
95
TearDown(void)96 void RdbWalLimitTest::TearDown(void)
97 {
98 if (resultSet != nullptr) {
99 EXPECT_EQ(resultSet->Close(), E_OK);
100 resultSet = nullptr;
101 }
102
103 store = nullptr;
104 RdbHelper::DeleteRdbStore(DATABASE_NAME);
105 }
106
CreateRandomData(int32_t len)107 std::vector<uint8_t> RdbWalLimitTest::CreateRandomData(int32_t len)
108 {
109 std::random_device randomDevice;
110 std::uniform_int_distribution<int> distribution(0, std::numeric_limits<uint8_t>::max());
111 std::vector<uint8_t> value(len);
112 for (int32_t i = 0; i < len; i++) {
113 value[i] = static_cast<uint8_t>(distribution(randomDevice));
114 }
115 return value;
116 }
117
KeepReadConnection()118 void RdbWalLimitTest::KeepReadConnection()
119 {
120 int64_t id;
121 ValuesBucket values;
122 values.PutInt("id", 1);
123 values.PutString("name", std::string("lisi"));
124 values.PutInt("age", 18);
125 values.PutDouble("salary", 200.8);
126 values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
127 EXPECT_EQ(store->Insert(id, "test", values), E_OK);
128
129 resultSet = store->QueryByStep("SELECT * FROM test");
130 EXPECT_NE(resultSet, nullptr);
131
132 int count = 0;
133 EXPECT_EQ(resultSet->GetRowCount(count), E_OK);
134 EXPECT_EQ(count, 1);
135
136 EXPECT_EQ(resultSet->GoToFirstRow(), E_OK);
137 }
138
MakeWalIncrease()139 void RdbWalLimitTest::MakeWalIncrease()
140 {
141 int64_t id;
142 ValuesBucket values;
143 for (int i = 1; i < 199; i++) {
144 values.Clear();
145 values.PutInt("id", i);
146 values.PutString("name", std::string("lisi"));
147 values.PutInt("age", 18);
148 values.PutDouble("salary", 200.8);
149 values.PutBlob("blobType", blobValue);
150 EXPECT_EQ(store->Insert(id, "test", values), E_OK);
151 }
152 }
153
MakeWalReachLimit()154 void RdbWalLimitTest::MakeWalReachLimit()
155 {
156 int64_t id;
157 int i = 1;
158 int ret = E_OK;
159 ValuesBucket values;
160 while (ret == E_OK) {
161 i++;
162 values.Clear();
163 values.PutInt("id", i);
164 values.PutString("name", std::string("lisi"));
165 values.PutInt("age", 18);
166 values.PutDouble("salary", 200.8);
167 values.PutBlob("blobType", blobValue);
168 ret = store->Insert(id, "test", values);
169 }
170 }
171
MakeWalNoReachLimit()172 void RdbWalLimitTest::MakeWalNoReachLimit()
173 {
174 int64_t id;
175 ValuesBucket values;
176 for (int i = 2; i < 20; i++) {
177 values.Clear();
178 values.PutInt("id", i);
179 values.PutString("name", std::string("lisi"));
180 values.PutInt("age", 18);
181 values.PutDouble("salary", 200.8);
182 values.PutBlob("blobType", blobValue);
183 EXPECT_EQ(store->Insert(id, "test", values), E_OK);
184 }
185 }
186
MakeValueBucket(const int & id)187 ValuesBucket RdbWalLimitTest::MakeValueBucket(const int &id)
188 {
189 ValuesBucket values;
190 values.PutInt("id", id);
191 values.PutString("name", std::string("lisi"));
192 values.PutInt("age", 18);
193 values.PutDouble("salary", 200.8);
194 values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
195 return values;
196 }
197
198 /**
199 * @tc.name: RdbStore_WalOverLimit_001
200 * @tc.desc: Without reading data or conducting transactions, if data is continuously written,
201 * the WAL size will not exceed the default limit.
202 * @tc.type: FUNC
203 * @tc.acquire: AR000HR0G5
204 */
205 HWTEST_F(RdbWalLimitTest, RdbStore_WalOverLimit_001, TestSize.Level1)
206 {
207 MakeWalIncrease();
208
209 int64_t id;
210
211 ValuesBucket values = MakeValueBucket(199);
212 values.PutBlob("blobType", blobValue);
213 EXPECT_EQ(store->Insert(id, "test", values), E_OK);
214
215 std::vector<ValuesBucket> valuesBuckets;
216 for (int i = 200; i < 210; i++) {
217 valuesBuckets.push_back(RdbWalLimitTest::MakeValueBucket(i));
218 }
219
220 int64_t insertNum = 0;
221 EXPECT_EQ(store->BatchInsert(insertNum, "test", valuesBuckets), E_OK);
222
223 EXPECT_EQ(store->ExecuteSql("DELETE FROM test"), E_OK);
224 }
225
226 /**
227 * @tc.name: RdbStore_WalOverLimit_002
228 * @tc.desc: Before the wal file exceeds the limit, both read and write can be executed normally.
229 * @tc.type: FUNC
230 * @tc.acquire: AR000HR0G5
231 */
232 HWTEST_F(RdbWalLimitTest, RdbStore_WalOverLimit_002, TestSize.Level1)
233 {
234 KeepReadConnection();
235 MakeWalNoReachLimit();
236 ValuesBucket values = MakeValueBucket(20);
237
238 std::vector<ValuesBucket> valuesBuckets;
239 for (int i = 21; i < 30; i++) {
240 valuesBuckets.push_back(MakeValueBucket(i));
241 }
242
243 int64_t insertNum = 0;
244 EXPECT_EQ(store->BatchInsert(insertNum, "test", valuesBuckets), E_OK);
245
246 EXPECT_EQ(store->ExecuteSql("DELETE FROM test"), E_OK);
247 }
248
249 /**
250 * @tc.name: RdbStore_WalOverLimit_003
251 * @tc.desc: During transactions, the size of the wal file may exceed the limit.
252 * @tc.type: FUNC
253 * @tc.acquire: AR000HR0G5
254 */
255 HWTEST_F(RdbWalLimitTest, RdbStore_WalOverLimit_003, TestSize.Level3)
256 {
257 ValuesBucket values = MakeValueBucket(200);
258 int64_t id;
259 store->BeginTransaction();
260 MakeWalReachLimit();
261 EXPECT_EQ(store->Insert(id, "test", values), E_WAL_SIZE_OVER_LIMIT);
262 int errCode = store->Commit();
263 EXPECT_EQ(errCode, E_OK);
264 }
265
266 /**
267 * @tc.name: RdbStore_WalOverLimit_003
268 * @tc.desc: During transactions, the size of the wal file may exceed the limit.
269 * @tc.type: FUNC
270 * @tc.acquire: AR000HR0G5
271 */
272 HWTEST_F(RdbWalLimitTest, RdbStore_WalOverLimit_004, TestSize.Level3)
273 {
274 ValuesBucket values = MakeValueBucket(200);
275 int64_t id;
276 store->BeginTransaction();
277 MakeWalReachLimit();
278 EXPECT_EQ(store->Insert(id, "test", values), E_WAL_SIZE_OVER_LIMIT);
279 int errCode = store->RollBack();
280 EXPECT_EQ(errCode, E_OK);
281 }