1 /*
2 * Copyright (c) 2025 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 <sys/stat.h>
17 #include <sys/types.h>
18 #include <string>
19 #include <chrono>
20 #include "accesstoken_kit.h"
21 #include "common.h"
22 #include "rdb_errno.h"
23 #include "relational_store.h"
24 #include "relational_store_error_code.h"
25 #include "relational_store_impl.h"
26 #include "token_setproc.h"
27
28 using namespace testing::ext;
29 using namespace OHOS::NativeRdb;
30 using namespace OHOS::Security::AccessToken;
31 using namespace OHOS::RdbNdk;
32
33 static constexpr int64_t BASE_COUNT = 1000; // loop times
34 static constexpr int64_t RDB_INSERT_BASELINE = 3000;
35 static constexpr int64_t RDB_UPDATE_BASELINE = 3000;
36 static constexpr int64_t TRANS_INSERT_BASELINE = 3000;
37 static constexpr int64_t TRANS_UPDATE_BASELINE = 3000;
38 static constexpr int64_t RDB_ATTACH_BASELINE = 6000; // attach and detach two interfaces together.
39
40 class RdbPerformanceTest : public testing::Test {
41 public:
42 static void SetUpTestCase(void);
43 static void TearDownTestCase(void);
44 void SetUp();
45 void TearDown();
InitRdbConfig()46 static void InitRdbConfig()
47 {
48 config_.dataBaseDir = RDB_TEST_PATH;
49 config_.storeName = "rdb_store_test.db";
50 config_.bundleName = "com.ohos.example.distributedndk";
51 config_.moduleName = "";
52 config_.securityLevel = OH_Rdb_SecurityLevel::S1;
53 config_.isEncrypt = false;
54 config_.selfSize = sizeof(OH_Rdb_Config);
55 config_.area = RDB_SECURITY_AREA_EL1;
56 }
57 static OH_Rdb_Config config_;
58 static void MockHap(void);
59 };
60
61 static OH_Rdb_Store *g_performanStore = nullptr;
62 static OH_RDB_TransOptions *g_options = nullptr;
63 OH_Rdb_Config RdbPerformanceTest::config_ = { 0 };
64
MockHap(void)65 void RdbPerformanceTest::MockHap(void)
66 {
67 HapInfoParams info = {
68 .userID = 100,
69 .bundleName = "com.example.distributed",
70 .instIndex = 0,
71 .appIDDesc = "com.example.distributed"
72 };
73 PermissionDef infoManagerTestPermDef = {
74 .permissionName = "ohos.permission.test",
75 .bundleName = "com.example.distributed",
76 .grantMode = 1,
77 .availableLevel = APL_NORMAL,
78 .label = "label",
79 .labelId = 1,
80 .description = "open the door",
81 .descriptionId = 1
82 };
83 PermissionStateFull infoManagerTestState = {
84 .permissionName = "ohos.permission.test",
85 .isGeneral = true,
86 .resDeviceID = { "local" },
87 .grantStatus = { PermissionState::PERMISSION_GRANTED },
88 .grantFlags = { 1 }
89 };
90 HapPolicyParams policy = {
91 .apl = APL_NORMAL,
92 .domain = "test.domain",
93 .permList = { infoManagerTestPermDef },
94 .permStateList = { infoManagerTestState }
95 };
96 AccessTokenKit::AllocHapToken(info, policy);
97 }
98
SetUpTestCase(void)99 void RdbPerformanceTest::SetUpTestCase(void)
100 {
101 MockHap();
102 InitRdbConfig();
103 // 0770 is permission
104 mkdir(config_.dataBaseDir, 0770);
105 int errCode = 0;
106 g_performanStore = OH_Rdb_GetOrOpen(&config_, &errCode);
107 EXPECT_NE(g_performanStore, NULL);
108
109 g_options = OH_RdbTrans_CreateOptions();
110 EXPECT_NE(g_options, nullptr);
111 int ret = OH_RdbTransOption_SetType(g_options, RDB_TRANS_BUTT);
112 EXPECT_EQ(ret, RDB_E_INVALID_ARGS);
113 ret = OH_RdbTransOption_SetType(g_options, RDB_TRANS_DEFERRED);
114 EXPECT_EQ(ret, RDB_OK);
115 }
116
TearDownTestCase(void)117 void RdbPerformanceTest::TearDownTestCase(void)
118 {
119 int errCode = OH_Rdb_CloseStore(g_performanStore);
120 EXPECT_EQ(errCode, 0);
121 errCode = OH_Rdb_DeleteStore(&config_);
122 EXPECT_EQ(errCode, 0);
123
124 OH_RdbTrans_DestroyOptions(g_options);
125 g_options = nullptr;
126 }
127
SetUp(void)128 void RdbPerformanceTest::SetUp(void)
129 {
130 char createTableSql[] = "CREATE TABLE store_test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 TEXT, data2 INTEGER, "
131 "data3 FLOAT, data4 BLOB, data5 TEXT);";
132 int errCode = OH_Rdb_Execute(g_performanStore, createTableSql);
133 EXPECT_EQ(errCode, 0);
134
135 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
136 valueBucket->putInt64(valueBucket, "id", 1);
137 valueBucket->putText(valueBucket, "data1", "zhangSan");
138 // 12800 test value.
139 valueBucket->putInt64(valueBucket, "data2", 12800);
140 // 100.1 test value.
141 valueBucket->putReal(valueBucket, "data3", 100.1);
142 uint8_t arr[] = { 1, 2, 3, 4, 5 };
143 int len = sizeof(arr) / sizeof(arr[0]);
144 valueBucket->putBlob(valueBucket, "data4", arr, len);
145 valueBucket->putText(valueBucket, "data5", "ABCDEFG");
146 errCode = OH_Rdb_Insert(g_performanStore, "store_test", valueBucket);
147 EXPECT_EQ(errCode, 1);
148
149 char querySql[] = "SELECT * FROM store_test";
150 OH_Cursor *cursor = OH_Rdb_ExecuteQuery(g_performanStore, querySql);
151
152 int rowCount = 0;
153 cursor->getRowCount(cursor, &rowCount);
154 EXPECT_EQ(rowCount, 1);
155 cursor->destroy(cursor);
156 valueBucket->destroy(valueBucket);
157 }
158
TearDown(void)159 void RdbPerformanceTest::TearDown(void)
160 {
161 char dropTableSql[] = "DROP TABLE IF EXISTS store_test";
162 int errCode = OH_Rdb_Execute(g_performanStore, dropTableSql);
163 EXPECT_EQ(errCode, 0);
164 }
165
166 /* *
167 * @tc.name: Trans_InsertWithConflictResolution_test_001
168 * @tc.desc: test OH_RdbTrans_InsertWithConflictResolution interface performance.
169 * @tc.type: FUNC
170 */
171 HWTEST_F(RdbPerformanceTest, Trans_InsertWithConflictResolution_test_001, TestSize.Level1)
172 {
173 OH_Rdb_Transaction *trans = nullptr;
174 const char *table = "store_test";
175 int ret = OH_Rdb_CreateTransaction(g_performanStore, g_options, &trans);
176 EXPECT_EQ(ret, RDB_OK);
177 EXPECT_NE(trans, nullptr);
178
179 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
180 valueBucket->putText(valueBucket, "data1", "test_name4");
181 // init is data2 is 14800
182 valueBucket->putInt64(valueBucket, "data2", 14800);
183 // init is data2 is 300.1
184 valueBucket->putReal(valueBucket, "data3", 300.1);
185 valueBucket->putText(valueBucket, "data5", "ABCDEFGHI");
186 int64_t rowId = -1;
187
188 auto now = std::chrono::system_clock::now().time_since_epoch();
189 int64_t start = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
190
191 for (int i = 0; i < BASE_COUNT; i++) {
192 ret = OH_RdbTrans_InsertWithConflictResolution(trans, table, valueBucket, RDB_CONFLICT_ROLLBACK, &rowId);
193 EXPECT_EQ(ret, RDB_OK);
194 }
195
196 now = std::chrono::system_clock::now().time_since_epoch();
197 int64_t summaryTime = (std::chrono::duration_cast<std::chrono::microseconds>(now).count() - start);
198 int64_t averageTime = summaryTime / BASE_COUNT;
199
200 EXPECT_LE(averageTime, RDB_INSERT_BASELINE);
201
202 valueBucket->destroy(valueBucket);
203 ret = OH_RdbTrans_Destroy(trans);
204 EXPECT_EQ(ret, RDB_OK);
205 }
206
207 /* *
208 * @tc.name: Trans_UpdateWithConflictResolution_test_002
209 * @tc.desc: test OH_RdbTrans_UpdateWithConflictResolution interface performance.
210 * @tc.type: FUNC
211 */
212 HWTEST_F(RdbPerformanceTest, Trans_UpdateWithConflictResolution_test_002, TestSize.Level1)
213 {
214 OH_Rdb_Transaction *trans = nullptr;
215 const char *table = "store_test";
216 int ret = OH_Rdb_CreateTransaction(g_performanStore, g_options, &trans);
217 EXPECT_EQ(ret, RDB_OK);
218 EXPECT_NE(trans, nullptr);
219
220 // new row
221 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
222 valueBucket->putText(valueBucket, "data1", "liSi");
223 // init data2 value is 13800
224 valueBucket->putInt64(valueBucket, "data2", 13800);
225 // init data3 value is 200.1
226 valueBucket->putReal(valueBucket, "data3", 200.1);
227 valueBucket->putNull(valueBucket, "data5");
228
229 // create predicates
230 OH_Predicates *predicates = OH_Rdb_CreatePredicates(table);
231 // create match data
232 OH_VObject *valueObject = OH_Rdb_CreateValueObject();
233 const char *data1Value = "zhangSan";
234 valueObject->putText(valueObject, data1Value);
235 predicates->equalTo(predicates, "data1", valueObject);
236
237 // update
238 int64_t changes = -1;
239 auto now = std::chrono::system_clock::now().time_since_epoch();
240 int64_t start = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
241
242 for (int i = 0; i < BASE_COUNT; i++) {
243 ret = OH_RdbTrans_UpdateWithConflictResolution(trans, valueBucket, predicates, RDB_CONFLICT_REPLACE, &changes);
244 EXPECT_EQ(ret, RDB_OK);
245 }
246
247 now = std::chrono::system_clock::now().time_since_epoch();
248 int64_t summaryTime = (std::chrono::duration_cast<std::chrono::microseconds>(now).count() - start);
249 int64_t averageTime = summaryTime / BASE_COUNT;
250
251 EXPECT_LE(averageTime, RDB_UPDATE_BASELINE);
252
253 // destroy
254 valueObject->destroy(valueObject);
255 valueBucket->destroy(valueBucket);
256 ret = OH_RdbTrans_Destroy(trans);
257 EXPECT_EQ(ret, RDB_OK);
258 }
259
260 /* *
261 * @tc.name: RDB_InsertWithConflictResolution_test_003
262 * @tc.desc: test OH_Rdb_InsertWithConflictResolution interface performance.
263 * @tc.type: FUNC
264 */
265 HWTEST_F(RdbPerformanceTest, RDB_InsertWithConflictResolution_test_003, TestSize.Level1)
266 {
267 int ret = 0;
268 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
269 valueBucket->putText(valueBucket, "data1", "liSi");
270 valueBucket->putInt64(valueBucket, "data2", 13800);
271 valueBucket->putReal(valueBucket, "data3", 200.1);
272 valueBucket->putText(valueBucket, "data5", "ABCDEFGH");
273 int64_t rowId = 0;
274
275 auto now = std::chrono::system_clock::now().time_since_epoch();
276 int64_t start = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
277
278 for (int i = 0; i < BASE_COUNT; i++) {
279 ret = OH_Rdb_InsertWithConflictResolution(g_performanStore, "store_test", valueBucket, RDB_CONFLICT_ROLLBACK,
280 &rowId);
281 EXPECT_EQ(ret, RDB_OK);
282 }
283
284 now = std::chrono::system_clock::now().time_since_epoch();
285 int64_t summaryTime = (std::chrono::duration_cast<std::chrono::microseconds>(now).count() - start);
286 int64_t averageTime = summaryTime / BASE_COUNT;
287
288 EXPECT_LE(averageTime, TRANS_INSERT_BASELINE);
289
290 valueBucket->destroy(valueBucket);
291 }
292
293 /* *
294 * @tc.name: RDB_UpdateWithConflictResolution_test_004
295 * @tc.desc: test OH_Rdb_UpdateWithConflictResolution interface performance.
296 * @tc.type: FUNC
297 */
298 HWTEST_F(RdbPerformanceTest, RDB_UpdateWithConflictResolution_test_004, TestSize.Level1)
299 {
300 int ret = 0;
301 OH_Predicates *predicates = OH_Rdb_CreatePredicates("store_test");
302 EXPECT_NE(predicates, NULL);
303
304 OH_VObject *valueObject = OH_Rdb_CreateValueObject();
305 EXPECT_NE(valueObject, NULL);
306 const char *data1Value = "zhangSan";
307 valueObject->putText(valueObject, data1Value);
308
309 predicates->equalTo(predicates, "data1", valueObject);
310
311 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
312 EXPECT_NE(valueBucket, NULL);
313 valueBucket->putText(valueBucket, "data1", "liSi");
314 valueBucket->putInt64(valueBucket, "data2", 13800);
315 valueBucket->putReal(valueBucket, "data3", 200.1);
316 valueBucket->putNull(valueBucket, "data5");
317
318 int64_t chgs = 0;
319 auto now = std::chrono::system_clock::now().time_since_epoch();
320 int64_t start = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
321
322 for (int i = 0; i < BASE_COUNT; i++) {
323 ret = OH_Rdb_UpdateWithConflictResolution(g_performanStore, valueBucket, predicates, RDB_CONFLICT_ROLLBACK,
324 &chgs);
325 EXPECT_EQ(ret, RDB_OK);
326 }
327
328 now = std::chrono::system_clock::now().time_since_epoch();
329 int64_t summaryTime = (std::chrono::duration_cast<std::chrono::microseconds>(now).count() - start);
330 int64_t averageTime = summaryTime / BASE_COUNT;
331
332 EXPECT_LE(averageTime, TRANS_UPDATE_BASELINE);
333
334 valueObject->destroy(valueObject);
335 valueBucket->destroy(valueBucket);
336 predicates->destroy(predicates);
337 }
338
339 /* *
340 * @tc.name: RDB_AttachAndDetach_test_005
341 * @tc.desc: Normal testCase of OH_Rdb_InsertWithConflictResolution errcode.
342 * @tc.type: FUNC
343 */
344 HWTEST_F(RdbPerformanceTest, RDB_AttachAndDetach_test_005, TestSize.Level1)
345 {
346 auto attachConfig = OH_Rdb_CreateConfig();
347 ASSERT_NE(attachConfig, nullptr);
348 OH_Rdb_SetDatabaseDir(attachConfig, RDB_TEST_PATH);
349 OH_Rdb_SetStoreName(attachConfig, "rdb_attach_store_test.db");
350 OH_Rdb_SetBundleName(attachConfig, "com.ohos.example.distributedndk");
351 OH_Rdb_SetEncrypted(attachConfig, false);
352 OH_Rdb_SetSecurityLevel(attachConfig, OH_Rdb_SecurityLevel::S1);
353 OH_Rdb_SetArea(attachConfig, RDB_SECURITY_AREA_EL1);
354
355 int errCode = 0;
356 auto tmpStore = OH_Rdb_CreateOrOpen(attachConfig, &errCode);
357 EXPECT_NE(tmpStore, NULL);
358 OH_Rdb_CloseStore(tmpStore);
359
360 size_t attachedNumber = 0;
361 auto now = std::chrono::system_clock::now().time_since_epoch();
362 int64_t start = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
363 for (int i = 0; i < BASE_COUNT; i++) {
364 auto ret = OH_Rdb_Attach(g_performanStore, attachConfig, "rdb_attach_test", 3, &attachedNumber);
365 EXPECT_EQ(ret, RDB_OK);
366
367 ret = OH_Rdb_Detach(g_performanStore, "rdb_attach_test", 3, &attachedNumber);
368 EXPECT_EQ(ret, RDB_OK);
369 }
370
371 now = std::chrono::system_clock::now().time_since_epoch();
372 int64_t summaryTime = (std::chrono::duration_cast<std::chrono::microseconds>(now).count() - start);
373 int64_t averageTime = summaryTime / BASE_COUNT;
374
375 EXPECT_LE(averageTime, RDB_ATTACH_BASELINE);
376 }