• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include <atomic>
18 #include <iostream>
19 #include <random>
20 #include <string>
21 #include <thread>
22 
23 #include "gdb_errors.h"
24 #include "executor_pool.h"
25 #include "grd_adapter_manager.h"
26 #include "gdb_helper.h"
27 #include "gdb_store.h"
28 #include "path.h"
29 
30 using namespace testing::ext;
31 using namespace OHOS::DistributedDataAip;
32 class GdbMultiThreadTest : public testing::Test {
33 public:
34     static void SetUpTestCase(void);
35     static void TearDownTestCase(void);
36     void SetUp();
37     void TearDown();
38     void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age);
39     void MatchAndVerifyPerson(const std::string &name, const int32_t &age, std::shared_ptr<DBStore> store);
40     void MultiThreadExecuteInsert(std::shared_ptr<DBStore> store);
41     void MultiThreadExecuteDBStore();
42     void MultiThreadInsertRelation(std::shared_ptr<DBStore> store);
43     void MultiThreadQueryRelation(std::shared_ptr<DBStore> store);
44     std::string RandomString(size_t length);
45 
46 protected:
47     std::atomic<int> counter;
48     static const std::string databaseName;
49     static const std::string databasePath;
50     static const std::string createGraphGql;
51     std::shared_ptr<OHOS::ExecutorPool> executors_;
52 };
53 const std::string GdbMultiThreadTest::databaseName = "execute_test";
54 const std::string GdbMultiThreadTest::databasePath = "/data";
55 const std::string GdbMultiThreadTest::createGraphGql = "CREATE GRAPH test { "
56                                                        "(person:Person {name STRING, age INT, sex BOOL DEFAULT false}),"
57                                                        "(dog:Dog {name STRING, age INT}), "
58                                                        "(person) -[:Friend]-> (person) "
59                                                        "};";
60 
SetUpTestCase(void)61 void GdbMultiThreadTest::SetUpTestCase(void)
62 {
63     if (!IsSupportArkDataDb()) {
64         GTEST_SKIP() << "Current testcase is not compatible from current gdb";
65         return;
66     }
67 }
68 
TearDownTestCase(void)69 void GdbMultiThreadTest::TearDownTestCase(void)
70 {
71 }
72 
SetUp()73 void GdbMultiThreadTest::SetUp()
74 {
75     if (!IsSupportArkDataDb()) {
76         GTEST_SKIP() << "Current testcase is not compatible from current gdb";
77         return;
78     }
79     int32_t maxThread = 5;
80     int32_t minThread = 0;
81     executors_ = std::make_shared<OHOS::ExecutorPool>(maxThread, minThread);
82 }
83 
TearDown()84 void GdbMultiThreadTest::TearDown()
85 {
86     executors_ = nullptr;
87 }
88 
89 /**
90  * @tc.name: MultiThread_GetDBStore_0001
91  * @tc.desc: Start two threads to open the database.
92  * @tc.type: FUNC
93  */
94 HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0001, TestSize.Level2)
95 {
96     counter.store(0);
97     MultiThreadExecuteDBStore();
98     MultiThreadExecuteDBStore();
99     while (true) {
100         if (counter.load() == 100) {
101             break;
102         }
103     }
104 }
105 
106 /**
107  * @tc.name: MultiThreadExecuteDBStore
108  * @tc.desc: Start the database in the current thread for 50 times.
109  * @tc.type: FUNC
110  */
MultiThreadExecuteDBStore()111 void GdbMultiThreadTest::MultiThreadExecuteDBStore()
112 {
113     executors_->Execute([this]() {
114         int errCode = E_OK;
115         std::string dbName = RandomString(10) + RandomString(10);
116         constexpr int32_t COUNT = 50;
117         for (uint32_t j = 0; j < COUNT; j++) {
118             auto config = StoreConfig(dbName + std::to_string(j), databasePath);
119             GDBHelper::DeleteDBStore(config);
120             auto store = GDBHelper::GetDBStore(config, errCode);
121             auto result = store->ExecuteGql(createGraphGql);
122             EXPECT_NE(store, nullptr);
123             EXPECT_EQ(result.first, E_OK);
124             ASSERT_NE(result.second, nullptr);
125 
126             result = store->ExecuteGql("DROP GRAPH test");
127             EXPECT_NE(store, nullptr);
128             EXPECT_EQ(result.first, E_OK);
129             GDBHelper::DeleteDBStore(config);
130             counter.fetch_add(1, std::memory_order_relaxed);
131         }
132     });
133 }
134 
135 /**
136  * @tc.name: MultiThread_GetDBStore_0002
137  * @tc.desc: Start two threads to test the insertion Vertex and Edge.
138  * @tc.type: FUNC
139  */
140 HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0002, TestSize.Level2)
141 {
142     int errCode = E_OK;
143     auto config = StoreConfig(databaseName + "test22", databasePath);
144     auto store = GDBHelper::GetDBStore(config, errCode);
145     auto result = store->ExecuteGql(createGraphGql);
146     EXPECT_NE(store, nullptr);
147     EXPECT_EQ(result.first, E_OK);
148     ASSERT_NE(result.second, nullptr);
149     counter.store(0);
150     MultiThreadExecuteInsert(store);
151     sleep(1);
152     MultiThreadExecuteInsert(store);
153     while (true) {
154         // counter ++ 200
155         if (counter.load() == 200) {
156             break;
157         }
158     }
159     sleep(1);
160     result = store->ExecuteGql("DROP GRAPH test");
161     EXPECT_NE(store, nullptr);
162     EXPECT_EQ(result.first, E_OK);
163     GDBHelper::DeleteDBStore(config);
164 }
165 
166 /**
167  * @tc.name: MultiThreadExecuteInsert
168  * @tc.desc: Start threads to test the insertion Vertex and Edge.
169  * @tc.type: FUNC
170  */
MultiThreadExecuteInsert(std::shared_ptr<DBStore> store)171 void GdbMultiThreadTest::MultiThreadExecuteInsert(std::shared_ptr<DBStore> store)
172 {
173     executors_->Execute([this, &store]() {
174         std::string nameStr = RandomString(10) + RandomString(10);
175         constexpr int32_t MAX_COUNT = 100;
176         for (uint32_t j = 0; j < MAX_COUNT; j++) {
177             std::string name = nameStr + std::to_string(j);
178             auto result = store->ExecuteGql("INSERT (:Person {name: '" + name + "', age: 11});");
179             EXPECT_EQ(result.first, E_OK);
180             constexpr int32_t AGE_11 = 11;
181             MatchAndVerifyPerson(name, AGE_11, store);
182 
183             std::string name2 = name + std::to_string(j);
184             result = store->ExecuteGql("INSERT (:Person {name: '" + name2 + "', age: 22});");
185             EXPECT_EQ(result.first, E_OK);
186             constexpr int32_t AGE = 22;
187             MatchAndVerifyPerson(name2, AGE, store);
188 
189             std::string name3 = name2 + std::to_string(j);
190             result = store->ExecuteGql("INSERT (:Person {name: '" + name3 + "', age: 33});");
191             EXPECT_EQ(result.first, E_OK);
192             constexpr int32_t AGE_33 = 33;
193             MatchAndVerifyPerson(name3, AGE_33, store);
194 
195             result = store->ExecuteGql("MATCH (p1:Person {name: '" + name + "'}), (p2:Person {name: '" + name2 +
196                                        "'}) INSERT (p1)-[:Friend]->(p2);");
197             EXPECT_EQ(result.first, E_OK);
198             result = store->ExecuteGql("MATCH (p1:Person {name: '" + name2 + "'}), (p2:Person {name: '" + name3 +
199                                        "'}) INSERT (p1)-[:Friend]->(p2);");
200             EXPECT_EQ(result.first, E_OK);
201 
202             result = store->QueryGql(
203                 "MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;");
204             ASSERT_EQ(result.first, E_OK);
205 
206             auto result2 = store->QueryGql("MATCH path=(a:Person {name: '" + name +
207                                            "'})-[]->{2, 2}(b:Person {name: '" + name3 + "'}) RETURN path;");
208             ASSERT_EQ(result2.first, E_OK);
209             counter.fetch_add(1, std::memory_order_relaxed);
210         }
211     });
212 }
213 
214 /**
215  * @tc.name: MultiThread_GetDBStore_0003
216  * @tc.desc: Start two threads to insert edges of the same Vertex, and start another thread to query edges.
217  * @tc.type: FUNC
218  */
219 HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0003, TestSize.Level2)
220 {
221     int errCode = E_OK;
222     auto config = StoreConfig(databaseName + "test33", databasePath);
223     auto store = GDBHelper::GetDBStore(config, errCode);
224     auto result = store->ExecuteGql(createGraphGql);
225     EXPECT_NE(store, nullptr);
226     EXPECT_EQ(result.first, E_OK);
227     ASSERT_NE(result.second, nullptr);
228     counter.store(0);
229 
230     std::string name = "zhangsan";
231     result = store->ExecuteGql("INSERT (:Person {name: '" + name + "', age: 11});");
232     EXPECT_EQ(result.first, E_OK);
233     constexpr int32_t AGE_11 = 11;
234     MatchAndVerifyPerson(name, AGE_11, store);
235     //insert Vertex and edge
236     MultiThreadInsertRelation(store);
237     MultiThreadInsertRelation(store);
238     sleep(1);
239     //query Vertex and edge
240     MultiThreadExecuteInsert(store);
241     while (true) {
242         if (counter.load() == 300) {
243             break;
244         }
245     }
246     // query match count is 200
247     result =
248         store->QueryGql("MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;");
249     ASSERT_EQ(result.first, E_OK);
250     EXPECT_EQ(result.second->GetAllData().size(), 200);
251 
252     result = store->ExecuteGql("DROP GRAPH test");
253     EXPECT_NE(store, nullptr);
254     EXPECT_EQ(result.first, E_OK);
255     GDBHelper::DeleteDBStore(config);
256 }
257 
MultiThreadInsertRelation(std::shared_ptr<DBStore> store)258 void GdbMultiThreadTest::MultiThreadInsertRelation(std::shared_ptr<DBStore> store)
259 {
260     executors_->Execute([this, &store]() {
261         std::string nameStr = RandomString(10) + RandomString(10);
262         std::string name = "zhangsan";
263         constexpr int32_t MAX_COUNT = 100;
264         for (uint32_t j = 0; j < MAX_COUNT; j++) {
265             std::string name2 = nameStr + std::to_string(j);
266             auto result = store->ExecuteGql("INSERT (:Person {name: '" + name2 + "', age: 22});");
267             EXPECT_EQ(result.first, E_OK);
268             constexpr int32_t AGE = 22;
269             MatchAndVerifyPerson(name2, AGE, store);
270 
271             result = store->ExecuteGql("MATCH (p1:Person {name: '" + name + "'}), (p2:Person {name: '" + name2 +
272                                        "'}) INSERT (p1)-[:Friend]->(p2);");
273             EXPECT_EQ(result.first, E_OK);
274             counter.fetch_add(1, std::memory_order_relaxed);
275         }
276     });
277 }
278 
MultiThreadQueryRelation(std::shared_ptr<DBStore> store)279 void GdbMultiThreadTest::MultiThreadQueryRelation(std::shared_ptr<DBStore> store)
280 {
281     executors_->Execute([this, &store]() {
282         std::string name = "zhangsan";
283         constexpr int32_t MAX_COUNT = 100;
284         for (uint32_t j = 0; j < MAX_COUNT; j++) {
285             auto result = store->QueryGql(
286                 "MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;");
287             ASSERT_EQ(result.first, E_OK);
288             counter.fetch_add(1, std::memory_order_relaxed);
289         }
290     });
291 }
292 
RandomString(size_t length)293 std::string GdbMultiThreadTest::RandomString(size_t length)
294 {
295     const std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
296     std::random_device rd;
297     std::mt19937 gen(rd());
298     std::uniform_int_distribution<> dis(0, letters.size() - 1);
299 
300     std::string randomStr;
301     for (size_t i = 0; i < length; ++i) {
302         randomStr.push_back(letters[dis(gen)]);
303     }
304     return randomStr;
305 }
306 
MatchAndVerifyPerson(const std::string & name,const int32_t & age,std::shared_ptr<DBStore> store)307 void GdbMultiThreadTest::MatchAndVerifyPerson(
308     const std::string &name, const int32_t &age, std::shared_ptr<DBStore> store)
309 {
310     EXPECT_NE(store, nullptr);
311     auto gql = "MATCH (person:Person {name: '" + name + "', age: " + std::to_string(age) + "}) RETURN person;";
312     auto result = store->QueryGql(gql);
313     ASSERT_EQ(result.first, E_OK);
314     ASSERT_NE(result.second, nullptr);
315     ASSERT_EQ(result.second->GetAllData().size(), 1);
316     GraphValue person = result.second->GetAllData()[0]["person"];
317     VerifyPersonInfo(person, name, age);
318 }
319 
VerifyPersonInfo(const GraphValue & person,const std::string & name,const int32_t & age)320 void GdbMultiThreadTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age)
321 {
322     auto expectSize = 3;
323     ASSERT_TRUE(std::holds_alternative<std::shared_ptr<Vertex>>(person));
324     auto personVertex = std::get<std::shared_ptr<Vertex>>(person);
325     EXPECT_EQ(personVertex->GetLabel(), "Person");
326     ASSERT_EQ(personVertex->GetProperties().size(), expectSize);
327 
328     auto nameDb = personVertex->GetProperties().find("name");
329     ASSERT_NE(nameDb, personVertex->GetProperties().end());
330     ASSERT_TRUE(std::holds_alternative<std::string>(nameDb->second));
331     EXPECT_EQ(std::get<std::string>(nameDb->second), name);
332 
333     auto ageDb = personVertex->GetProperties().find("age");
334     ASSERT_NE(ageDb, personVertex->GetProperties().end());
335     ASSERT_TRUE(std::holds_alternative<int64_t>(ageDb->second));
336     EXPECT_EQ(std::get<int64_t>(ageDb->second), age);
337 
338     auto sex = personVertex->GetProperties().find("sex");
339     ASSERT_NE(sex, personVertex->GetProperties().end());
340     ASSERT_TRUE(std::holds_alternative<int64_t>(sex->second));
341     EXPECT_EQ(std::get<int64_t>(sex->second), 0);
342 }