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
16 #include "gdb_transaction.h"
17
18 #include <gtest/gtest.h>
19
20 #include <cstdint>
21 #include <memory>
22 #include <string>
23 #include <thread>
24 #include <variant>
25
26 #include "edge.h"
27 #include "full_result.h"
28 #include "gdb_errors.h"
29 #include "gdb_helper.h"
30 #include "gdb_store.h"
31 #include "grd_adapter_manager.h"
32 #include "path.h"
33 #include "result.h"
34 #include "vertex.h"
35
36 using namespace testing::ext;
37 using namespace OHOS::DistributedDataAip;
38
39 using Transaction = OHOS::DistributedDataAip::Transaction;
40
41 class GdbTransactionTest : public testing::Test {
42 public:
43 static void SetUpTestCase();
44 static void TearDownTestCase();
45 void SetUp();
46 void TearDown();
47 void InsertPerson(const std::string &name, const int32_t &age, std::shared_ptr<Transaction> trans = nullptr);
48 void MatchAndVerifyPerson(const std::string &name, const int32_t &age,
49 std::shared_ptr<Transaction> trans = nullptr, bool hasData = true);
50 void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age);
51
52 static const std::string databaseName;
53 static const std::string databasePath;
54
55 static const std::string createGraphGql;
56
57 static std::shared_ptr<DBStore> store_;
58 };
59
60 const std::string GdbTransactionTest::databaseName = "transaction_test";
61 const std::string GdbTransactionTest::databasePath = "/data";
62
63 const std::string GdbTransactionTest::createGraphGql = "CREATE GRAPH test { "
64 "(person:Person {name STRING, age INT, sex BOOL DEFAULT false}),"
65 "(dog:Dog {name STRING, age INT}), "
66 "(person) -[:Friend]-> (person) "
67 "};";
68
69 std::shared_ptr<DBStore> GdbTransactionTest::store_;
70
71 static constexpr int32_t MAX_GQL_LEN = 1024 * 1024;
72
73 static constexpr int32_t MAX_CNT = 4;
74
SetUpTestCase()75 void GdbTransactionTest::SetUpTestCase()
76 {
77 if (!IsSupportArkDataDb()) {
78 GTEST_SKIP() << "Current testcase is not compatible from current gdb";
79 return;
80 }
81 int errCode = E_OK;
82 auto config = StoreConfig(databaseName, databasePath);
83 GDBHelper::DeleteDBStore(config);
84
85 GdbTransactionTest::store_ = GDBHelper::GetDBStore(config, errCode);
86 }
87
TearDownTestCase()88 void GdbTransactionTest::TearDownTestCase()
89 {
90 GDBHelper::DeleteDBStore(StoreConfig(databaseName, databasePath));
91 GdbTransactionTest::store_ = nullptr;
92 }
93
SetUp()94 void GdbTransactionTest::SetUp()
95 {
96 if (!IsSupportArkDataDb()) {
97 GTEST_SKIP() << "Current testcase is not compatible from current gdb";
98 return;
99 }
100 auto result = store_->ExecuteGql(createGraphGql);
101 }
102
TearDown()103 void GdbTransactionTest::TearDown()
104 {
105 if (store_ != nullptr) {
106 auto result = store_->ExecuteGql("DROP GRAPH test");
107 }
108 }
109
InsertPerson(const std::string & name,const int32_t & age,std::shared_ptr<Transaction> trans)110 void GdbTransactionTest::InsertPerson(const std::string &name, const int32_t &age, std::shared_ptr<Transaction> trans)
111 {
112 ASSERT_NE(store_, nullptr);
113 int32_t errCode = E_OK;
114 std::shared_ptr<Result> result = std::make_shared<FullResult>();
115 std::string gql = "INSERT (:Person {name: '" + name + "', age: " + std::to_string(age) + "});";
116 if (trans == nullptr) {
117 std::tie(errCode, result) = store_->ExecuteGql(gql);
118 } else {
119 ASSERT_NE(trans, nullptr);
120 std::tie(errCode, result) = trans->Execute(gql);
121 }
122 EXPECT_EQ(errCode, E_OK);
123 }
124
MatchAndVerifyPerson(const std::string & name,const int32_t & age,std::shared_ptr<Transaction> trans,bool hasData)125 void GdbTransactionTest::MatchAndVerifyPerson(const std::string &name, const int32_t &age,
126 std::shared_ptr<Transaction> trans, bool hasData)
127 {
128 ASSERT_NE(store_, nullptr);
129 int32_t errCode = E_OK;
130 std::shared_ptr<Result> result = std::make_shared<FullResult>();
131 std::string gql = "MATCH (person:Person {name: '" + name + "'}) RETURN person;";
132 if (trans == nullptr) {
133 std::tie(errCode, result) = store_->QueryGql(gql);
134 } else {
135 ASSERT_NE(trans, nullptr);
136 std::tie(errCode, result) = trans->Query(gql);
137 }
138 ASSERT_EQ(errCode, E_OK);
139 ASSERT_NE(result, nullptr);
140 if (!hasData) {
141 EXPECT_EQ(result->GetAllData().size(), 0);
142 return;
143 }
144 EXPECT_EQ(result->GetAllData().size(), 1);
145 GraphValue person = result->GetAllData()[0]["person"];
146 VerifyPersonInfo(person, name, age);
147 }
148
VerifyPersonInfo(const GraphValue & person,const std::string & name,const int32_t & age)149 void GdbTransactionTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age)
150 {
151 auto expectSize = 3;
152 ASSERT_TRUE(std::holds_alternative<std::shared_ptr<Vertex>>(person));
153 auto personVertex = std::get<std::shared_ptr<Vertex>>(person);
154 EXPECT_EQ(personVertex->GetLabel(), "Person");
155 ASSERT_EQ(personVertex->GetProperties().size(), expectSize);
156
157 auto nameDb = personVertex->GetProperties().find("name");
158 ASSERT_NE(nameDb, personVertex->GetProperties().end());
159 ASSERT_TRUE(std::holds_alternative<std::string>(nameDb->second));
160 EXPECT_EQ(std::get<std::string>(nameDb->second), name);
161
162 auto ageDb = personVertex->GetProperties().find("age");
163 ASSERT_NE(ageDb, personVertex->GetProperties().end());
164 ASSERT_TRUE(std::holds_alternative<int64_t>(ageDb->second));
165 EXPECT_EQ(std::get<int64_t>(ageDb->second), age);
166
167 auto sex = personVertex->GetProperties().find("sex");
168 ASSERT_NE(sex, personVertex->GetProperties().end());
169 ASSERT_TRUE(std::holds_alternative<int64_t>(sex->second));
170 EXPECT_EQ(std::get<int64_t>(sex->second), 0);
171 }
172
173 /**
174 * @tc.name: GdbTransactionTest001_CreateTransaction_Normal
175 * @tc.desc: test CreateTransaction
176 * @tc.type: FUNC
177 */
178 HWTEST_F(GdbTransactionTest, GdbTransactionTest001_CreateTransaction_Normal, TestSize.Level1)
179 {
180 ASSERT_NE(store_, nullptr);
181
182 auto [err1, trans1] = store_->CreateTransaction();
183 EXPECT_EQ(err1, E_OK);
184 EXPECT_NE(trans1, nullptr);
185
186 auto [err2, trans2] = store_->CreateTransaction();
187 EXPECT_EQ(err2, E_OK);
188 EXPECT_NE(trans2, nullptr);
189
190 auto [err3, trans3] = store_->CreateTransaction();
191 EXPECT_EQ(err3, E_OK);
192 EXPECT_NE(trans3, nullptr);
193
194 auto [err4, trans4] = store_->CreateTransaction();
195 EXPECT_EQ(err4, E_OK);
196 EXPECT_NE(trans4, nullptr);
197
198 err4 = trans4->Commit();
199 EXPECT_EQ(err4, E_OK);
200
201 auto [err5, trans5] = store_->CreateTransaction();
202 EXPECT_EQ(err5, E_OK);
203 EXPECT_NE(trans5, nullptr);
204 }
205
206 /**
207 * @tc.name: GdbTransactionTest002_CreateTransaction_Abnormal
208 * @tc.desc: test CreateTransaction upper bound
209 * @tc.type: FUNC
210 */
211 HWTEST_F(GdbTransactionTest, GdbTransactionTest002_CreateTransaction_Abnormal, TestSize.Level1)
212 {
213 ASSERT_NE(store_, nullptr);
214
215 auto [err1, trans1] = store_->CreateTransaction();
216 EXPECT_EQ(err1, E_OK);
217 EXPECT_NE(trans1, nullptr);
218
219 auto [err2, trans2] = store_->CreateTransaction();
220 EXPECT_EQ(err2, E_OK);
221 EXPECT_NE(trans2, nullptr);
222
223 auto [err3, trans3] = store_->CreateTransaction();
224 EXPECT_EQ(err3, E_OK);
225 EXPECT_NE(trans3, nullptr);
226
227 auto [err4, trans4] = store_->CreateTransaction();
228 EXPECT_EQ(err4, E_OK);
229 EXPECT_NE(trans4, nullptr);
230
231 auto [err5, trans5] = store_->CreateTransaction();
232 EXPECT_EQ(err5, E_DATABASE_BUSY);
233 EXPECT_EQ(trans5, nullptr);
234 }
235
236 /**
237 * @tc.name: GdbTransactionTest003_Query_Execute_Normal
238 * @tc.desc: test Transaction::Query and Transaction::Execute
239 * @tc.type: FUNC
240 */
241 HWTEST_F(GdbTransactionTest, GdbTransactionTest003_Query_Execute_Normal, TestSize.Level1)
242 {
243 InsertPerson("name_1", 11);
244
245 auto [err, trans] = store_->CreateTransaction();
246 EXPECT_EQ(err, E_OK);
247 EXPECT_NE(trans, nullptr);
248
249 MatchAndVerifyPerson("name_1", 11, trans);
250
251 InsertPerson("name_2", 22, trans);
252
253 MatchAndVerifyPerson("name_2", 22, trans);
254 }
255
256 /**
257 * @tc.name: GdbTransactionTest004_Query_Execute_Abnormal
258 * @tc.desc: test Transaction::Query and Transaction::Execute with invalid gql
259 * @tc.type: FUNC
260 */
261 HWTEST_F(GdbTransactionTest, GdbTransactionTest004_Query_Execute_Abnormal, TestSize.Level1)
262 {
263 InsertPerson("name_1", 11);
264
265 auto [err, trans] = store_->CreateTransaction();
266 EXPECT_EQ(err, E_OK);
267 EXPECT_NE(trans, nullptr);
268
269 int32_t errCode = E_OK;
270 std::shared_ptr<Result> result = std::make_shared<FullResult>();
271 std::string gql = "";
272 std::tie(errCode, result) = trans->Query(gql);
273 EXPECT_EQ(errCode, E_INVALID_ARGS);
274
275 std::tie(errCode, result) = trans->Execute(gql);
276 EXPECT_EQ(errCode, E_INVALID_ARGS);
277
278 for (int i = 0; i <= MAX_GQL_LEN; i++) {
279 gql += "I";
280 }
281 std::tie(errCode, result) = trans->Query(gql);
282 EXPECT_EQ(errCode, E_INVALID_ARGS);
283
284 std::tie(errCode, result) = trans->Execute(gql);
285 EXPECT_EQ(errCode, E_INVALID_ARGS);
286
287 gql = "MATCH (person:Person {name: 11}) RETURN person;";
288 std::tie(errCode, result) = trans->Query(gql);
289 EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR);
290
291 std::tie(err, trans) = store_->CreateTransaction();
292 EXPECT_EQ(err, E_OK);
293 EXPECT_NE(trans, nullptr);
294 gql = "INSERT (:Person {name: 11, age: 'name_1'});";
295 std::tie(errCode, result) = trans->Execute(gql);
296 EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR);
297
298 std::tie(err, trans) = store_->CreateTransaction();
299 EXPECT_EQ(err, E_OK);
300 EXPECT_NE(trans, nullptr);
301 gql = "MATCH;";
302 std::tie(errCode, result) = trans->Query(gql);
303 EXPECT_EQ(errCode, E_GRD_SYNTAX_ERROR);
304
305 std::tie(err, trans) = store_->CreateTransaction();
306 EXPECT_EQ(err, E_OK);
307 EXPECT_NE(trans, nullptr);
308 gql = "INSERT;";
309 std::tie(errCode, result) = trans->Execute(gql);
310 EXPECT_EQ(errCode, E_GRD_SYNTAX_ERROR);
311 }
312
313 /**
314 * @tc.name: GdbTransactionTest005_Commit_Normal
315 * @tc.desc: test Transaction::Commit
316 * @tc.type: FUNC
317 */
318 HWTEST_F(GdbTransactionTest, GdbTransactionTest005_Commit_Normal, TestSize.Level1)
319 {
320 ASSERT_NE(store_, nullptr);
321
322 auto [err, trans] = store_->CreateTransaction();
323 EXPECT_EQ(err, E_OK);
324 EXPECT_NE(trans, nullptr);
325
326 InsertPerson("name_1", 11, trans);
327
328 auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;";
329 auto result = store_->QueryGql(gql);
330 EXPECT_EQ(result.first, E_DATABASE_BUSY);
331
332 auto errCode = trans->Commit();
333 EXPECT_EQ(errCode, E_OK);
334
335 MatchAndVerifyPerson("name_1", 11);
336 }
337
338 /**
339 * @tc.name: GdbTransactionTest006_Commit_Abnormal
340 * @tc.desc: test Transaction::Commit
341 * @tc.type: FUNC
342 */
343 HWTEST_F(GdbTransactionTest, GdbTransactionTest006_Commit_Abnormal, TestSize.Level1)
344 {
345 ASSERT_NE(store_, nullptr);
346
347 auto [err, trans] = store_->CreateTransaction();
348 EXPECT_EQ(err, E_OK);
349 ASSERT_NE(trans, nullptr);
350
351 auto errCode = trans->Commit();
352 EXPECT_EQ(errCode, E_OK);
353
354 errCode = trans->Commit();
355 EXPECT_EQ(errCode, E_GRD_DB_INSTANCE_ABNORMAL);
356 }
357
358 /**
359 * @tc.name: GdbTransactionTest007_Rollback_Normal
360 * @tc.desc: test Transaction::Rollback
361 * @tc.type: FUNC
362 */
363 HWTEST_F(GdbTransactionTest, GdbTransactionTest007_Rollback_Normal, TestSize.Level1)
364 {
365 ASSERT_NE(store_, nullptr);
366
367 auto [err, trans] = store_->CreateTransaction();
368 EXPECT_EQ(err, E_OK);
369 EXPECT_NE(trans, nullptr);
370
371 InsertPerson("name_1", 11, trans);
372
373 auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;";
374 auto result = store_->QueryGql(gql);
375 EXPECT_EQ(result.first, E_DATABASE_BUSY);
376
377 auto errCode = trans->Rollback();
378 EXPECT_EQ(errCode, E_OK);
379
380 MatchAndVerifyPerson("name_1", 11, nullptr, false);
381 }
382
383 /**
384 * @tc.name: GdbTransactionTest008_Rollback_Abnormal
385 * @tc.desc: test Transaction::Rollback
386 * @tc.type: FUNC
387 */
388 HWTEST_F(GdbTransactionTest, GdbTransactionTest008_Rollback_Abnormal, TestSize.Level1)
389 {
390 ASSERT_NE(store_, nullptr);
391
392 auto [err, trans] = store_->CreateTransaction();
393 EXPECT_EQ(err, E_OK);
394 ASSERT_NE(trans, nullptr);
395
396 auto errCode = trans->Rollback();
397 EXPECT_EQ(errCode, E_OK);
398
399 errCode = trans->Rollback();
400 EXPECT_EQ(errCode, E_GRD_DB_INSTANCE_ABNORMAL);
401 }
402
403 /**
404 * @tc.name: GdbTransactionTest009_Isolation001
405 * @tc.desc: test Transaction
406 * @tc.type: FUNC
407 */
408 HWTEST_F(GdbTransactionTest, GdbTransactionTest009_Isolation001, TestSize.Level1)
409 {
410 ASSERT_NE(store_, nullptr);
411
412 auto [err1, trans1] = store_->CreateTransaction();
413 EXPECT_EQ(err1, E_OK);
414 EXPECT_NE(trans1, nullptr);
415
416 auto [err2, trans2] = store_->CreateTransaction();
417 EXPECT_EQ(err2, E_OK);
418 EXPECT_NE(trans2, nullptr);
419
420 InsertPerson("name_1", 11, trans1);
421
422 auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;";
423 auto [errCode, result] = trans2->Query(gql);
424 EXPECT_EQ(errCode, E_DATABASE_BUSY);
425 }
426
427 /**
428 * @tc.name: GdbTransactionTest010_Isolation002
429 * @tc.desc: test Transaction
430 * @tc.type: FUNC
431 */
432 HWTEST_F(GdbTransactionTest, GdbTransactionTest010_Isolation002, TestSize.Level1)
433 {
434 ASSERT_NE(store_, nullptr);
435
436 auto [err1, trans1] = store_->CreateTransaction();
437 EXPECT_EQ(err1, E_OK);
438 EXPECT_NE(trans1, nullptr);
439
440 auto [err2, trans2] = store_->CreateTransaction();
441 EXPECT_EQ(err2, E_OK);
442 EXPECT_NE(trans2, nullptr);
443
444 InsertPerson("name_1", 11, trans1);
445
446 ASSERT_NE(trans1, nullptr);
447 auto errCode = trans1->Commit();
448 EXPECT_EQ(errCode, E_OK);
449
450 MatchAndVerifyPerson("name_1", 11, trans2);
451 }
452
453 /**
454 * @tc.name: GdbTransactionTest011_Isolation003
455 * @tc.desc: test Transaction
456 * @tc.type: FUNC
457 */
458 HWTEST_F(GdbTransactionTest, GdbTransactionTest011_Isolation003, TestSize.Level1)
459 {
460 ASSERT_NE(store_, nullptr);
461
462 auto [err1, trans1] = store_->CreateTransaction();
463 EXPECT_EQ(err1, E_OK);
464 EXPECT_NE(trans1, nullptr);
465
466 auto [err2, trans2] = store_->CreateTransaction();
467 EXPECT_EQ(err2, E_OK);
468 EXPECT_NE(trans2, nullptr);
469
470 InsertPerson("name_1", 11, trans1);
471
472 ASSERT_NE(trans1, nullptr);
473 auto errCode = trans1->Rollback();
474 EXPECT_EQ(errCode, E_OK);
475
476 MatchAndVerifyPerson("name_1", 11, trans2, false);
477 }
478
479 /**
480 * @tc.name: GdbTransactionTest012_Isolation004
481 * @tc.desc: test Transaction
482 * @tc.type: FUNC
483 */
484 HWTEST_F(GdbTransactionTest, GdbTransactionTest012_Isolation004, TestSize.Level1)
485 {
486 ASSERT_NE(store_, nullptr);
487
488 auto [err1, trans1] = store_->CreateTransaction();
489 EXPECT_EQ(err1, E_OK);
490 EXPECT_NE(trans1, nullptr);
491
492 auto [err2, trans2] = store_->CreateTransaction();
493 EXPECT_EQ(err2, E_OK);
494 EXPECT_NE(trans2, nullptr);
495
496 InsertPerson("name_1", 11, trans1);
497
498 ASSERT_NE(trans2, nullptr);
499 int32_t errCode = E_OK;
500 std::shared_ptr<Result> result = std::make_shared<FullResult>();
501 std::tie(errCode, result) = trans2->Execute("INSERT (:Person {name: 'name_2', age: 22});");
502 EXPECT_EQ(errCode, E_DATABASE_BUSY);
503
504 errCode = trans1->Commit();
505 EXPECT_EQ(errCode, E_OK);
506
507 InsertPerson("name_2", 22, trans2);
508 }
509
510 /**
511 * @tc.name: GdbTransactionTest013_Close
512 * @tc.desc: test Close
513 * @tc.type: FUNC
514 */
515 HWTEST_F(GdbTransactionTest, GdbTransactionTest013_Close, TestSize.Level1)
516 {
517 ASSERT_NE(store_, nullptr);
518
519 auto [err, trans] = store_->CreateTransaction();
520 EXPECT_EQ(err, E_OK);
521 EXPECT_NE(trans, nullptr);
522
523 InsertPerson("name_1", 11, trans);
524
525 ASSERT_NE(store_, nullptr);
526 int32_t errCode = store_->Close();
527 EXPECT_EQ(errCode, E_OK);
528 store_ = nullptr;
529
530 auto config = StoreConfig(databaseName, databasePath);
531 store_ = GDBHelper::GetDBStore(config, errCode);
532 EXPECT_EQ(errCode, E_OK);
533 ASSERT_NE(store_, nullptr);
534
535 MatchAndVerifyPerson("name_1", 11, nullptr, false);
536 }
537
538 /**
539 * @tc.name: GdbTransactionTest014_StartTransByExecute
540 * @tc.desc: test Execute("START TRANSACTION;"), Execute("COMMIT") and Execute("ROLLBACK")
541 * @tc.type: FUNC
542 */
543 HWTEST_F(GdbTransactionTest, GdbTransactionTest014_StartTransByExecute001, TestSize.Level1)
544 {
545 ASSERT_NE(store_, nullptr);
546
547 auto [err, result] = store_->ExecuteGql("START TRANSACTION;");
548 EXPECT_EQ(err, E_INVALID_ARGS);
549
550 std::tie(err, result) = store_->ExecuteGql("COMMIT;");
551 EXPECT_EQ(err, E_INVALID_ARGS);
552
553 std::tie(err, result) = store_->ExecuteGql("ROLLBACK;");
554 EXPECT_EQ(err, E_INVALID_ARGS);
555 }
556
557 /**
558 * @tc.name: GdbTransactionTest015_TransactionNestification
559 * @tc.desc: test Transaction Nestification
560 * @tc.type: FUNC
561 */
562 HWTEST_F(GdbTransactionTest, GdbTransactionTest015_TransactionNestification, TestSize.Level1)
563 {
564 ASSERT_NE(store_, nullptr);
565
566 auto [err1, trans1] = store_->CreateTransaction();
567 EXPECT_EQ(err1, E_OK);
568 EXPECT_NE(trans1, nullptr);
569
570 auto result = trans1->Execute("START TRANSACTION;");
571 EXPECT_EQ(result.first, E_INVALID_ARGS);
572 }
573
574 /**
575 * @tc.name: GdbTransactionTest016_TransactionMultiThread
576 * @tc.desc: test Transaction MultiThread
577 * @tc.type: FUNC
578 */
579 HWTEST_F(GdbTransactionTest, GdbTransactionTest016_TransactionMultiThread, TestSize.Level1)
580 {
581 std::thread th[MAX_CNT];
582 for (int32_t i = 0; i < MAX_CNT; i++) {
__anon7c642dd90102() 583 th[i] = std::thread([this, i] () {
584 ASSERT_NE(store_, nullptr);
585
586 auto [err, trans] = store_->CreateTransaction();
587 EXPECT_EQ(err, E_OK);
588 ASSERT_NE(trans, nullptr);
589
590 InsertPerson("name_" + std::to_string(i), i, trans);
591
592 err = trans->Commit();
593 EXPECT_EQ(err, E_OK);
594 });
595 }
596
597 for (int32_t i = 0; i < MAX_CNT; i++) {
598 th[i].join();
599 }
600
601 for (int32_t i = 0; i < MAX_CNT; i++) {
602 MatchAndVerifyPerson("name_" + std::to_string(i), i);
603 }
604 }
605