1 /*
2 * Copyright (c) 2021 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 "db_errno.h"
19 #include "db_common.h"
20 #include "distributeddb_data_generate_unit_test.h"
21 #include "log_print.h"
22 #include "platform_specific.h"
23
24 using namespace testing::ext;
25 using namespace DistributedDB;
26 using namespace DistributedDBUnitTest;
27
28 namespace {
29 std::string g_testDir;
30
31 // define some variables to init a KvStoreDelegateManager object.
32 KvStoreDelegateManager g_mgr(APP_ID, USER_ID);
33 KvStoreConfig g_config;
34
35 // define the g_kvDelegateCallback, used to get some information when open a kv store.
36 DBStatus g_kvDelegateStatus = INVALID_ARGS;
37
38 KvStoreNbDelegate *g_kvNbDelegatePtr = nullptr;
39 auto g_kvNbDelegateCallback = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback,
40 std::placeholders::_1, std::placeholders::_2, std::ref(g_kvDelegateStatus), std::ref(g_kvNbDelegatePtr));
41 }
42
43 class DistributedDBCommonTest : public testing::Test {
44 public:
45 static void SetUpTestCase(void);
46 static void TearDownTestCase(void);
47 void SetUp();
48 void TearDown();
49 };
50
SetUpTestCase(void)51 void DistributedDBCommonTest::SetUpTestCase(void)
52 {
53 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
54 g_config.dataDir = g_testDir;
55 g_mgr.SetKvStoreConfig(g_config);
56 }
57
TearDownTestCase(void)58 void DistributedDBCommonTest::TearDownTestCase(void) {}
59
SetUp(void)60 void DistributedDBCommonTest::SetUp(void)
61 {
62 DistributedDBToolsUnitTest::PrintTestCaseInfo();
63 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
64 }
65
TearDown(void)66 void DistributedDBCommonTest::TearDown(void)
67 {
68 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
69 LOGI("rm test db files error!");
70 }
71 }
72
73 /**
74 * @tc.name: RemoveAllFilesOfDirectory
75 * @tc.desc: Test delete all file and dir.
76 * @tc.type: FUNC
77 * @tc.require: AR000FN6G9
78 * @tc.author: sunpeng
79 */
80 HWTEST_F(DistributedDBCommonTest, RemoveAllFilesOfDirectory, TestSize.Level1)
81 {
82 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/dirLevel1_1/"), E_OK);
83 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/dirLevel1_1/" + "/dirLevel2_1/"), E_OK);
84 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/dirLevel1_1/" + "/dirLevel2_2/"), E_OK);
85 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/dirLevel1_1/" + "/dirLevel2_2/" + "/dirLevel3_1/"), E_OK);
86
87 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/fileLevel1_1"), E_OK);
88 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/dirLevel1_1/" + "/fileLevel2_1"), E_OK);
89 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/dirLevel1_1/" + "/dirLevel2_2/" +
90 "/dirLevel3_1/"+ "/fileLevel4_1/"), E_OK);
91
92 EXPECT_EQ(DBCommon::RemoveAllFilesOfDirectory(g_testDir), E_OK);
93
94 EXPECT_EQ(OS::CheckPathExistence(g_testDir), false);
95 }
96
97 #ifdef RUNNING_ON_LINUX
98 /**
99 * @tc.name: SameProcessReLockFile
100 * @tc.desc: Test same process repeat lock same file.
101 * @tc.type: FUNC
102 * @tc.require: AR000FN6G9
103 * @tc.author: sunpeng
104 */
105 HWTEST_F(DistributedDBCommonTest, SameProcessReLockFile, TestSize.Level1)
106 {
107 // block mode
108 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/blockmode"), E_OK);
109 OS::FileHandle fd;
110 EXPECT_EQ(OS::OpenFile(g_testDir + "/blockmode", fd), E_OK);
111
112 EXPECT_EQ(OS::FileLock(fd, true), E_OK);
113 EXPECT_EQ(OS::FileLock(fd, true), E_OK);
114
115 // normal mode
116 OS::FileHandle fd2;
117 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/normalmode"), E_OK);
118 EXPECT_EQ(OS::OpenFile(g_testDir + "/normalmode", fd2), E_OK);
119 EXPECT_EQ(OS::FileLock(fd2, true), E_OK);
120 EXPECT_EQ(OS::FileLock(fd2, true), E_OK);
121
122 // unlock
123 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
124 EXPECT_EQ(OS::FileUnlock(fd2), E_OK); // unlock success will close fd
125 }
126
127 /**
128 * @tc.name: SameProcessReUnLockFile
129 * @tc.desc: Test same process repeat lock same file.
130 * @tc.type: FUNC
131 * @tc.require: AR000FN6G9
132 * @tc.author: sunpeng
133 */
134 HWTEST_F(DistributedDBCommonTest, SameProcessReUnLockFile, TestSize.Level1)
135 {
136 // unlock normal file twice
137 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/normalmode"), E_OK);
138 OS::FileHandle fd;
139 EXPECT_EQ(OS::OpenFile(g_testDir + "/normalmode", fd), E_OK);
140 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
141 EXPECT_EQ(OS::FileUnlock(fd), E_OK); // unlock success will close fd
142
143 EXPECT_EQ(OS::FileLock(fd, true), -E_SYSTEM_API_FAIL);
144 EXPECT_EQ(OS::FileLock(fd, true), -E_SYSTEM_API_FAIL);
145 ASSERT_EQ(fd.handle, -1);
146
147 // block mode
148 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/blockmode"), E_OK);
149 EXPECT_EQ(OS::OpenFile(g_testDir + "/blockmode", fd), E_OK);
150
151 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
152 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
153
154 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
155 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
156 }
157
158 /**
159 * @tc.name: CalcFileSizeTest
160 * @tc.desc: Test the file size for function test and the performance test.
161 * @tc.type: FUNC
162 * @tc.require: AR000FN6G9
163 * @tc.author: wangbingquan
164 */
165 HWTEST_F(DistributedDBCommonTest, CalcFileSizeTest, TestSize.Level1)
166 {
167 std::string filePath = g_testDir + "/testFileSize";
168 std::ofstream ofs(filePath, std::ofstream::out);
169 ASSERT_TRUE(ofs.good());
170 ofs << "test file size";
171 ofs.close();
172 uint64_t fileSize = 0;
173 EXPECT_EQ(OS::CalFileSize(filePath, fileSize), E_OK);
174 EXPECT_GT(fileSize, 0ULL);
175 EXPECT_EQ(OS::RemoveFile(filePath), E_OK);
176 }
177
178 // Distributed db is not recommended to use multiple processes to access
179 // This testcase only guard for some wrong use on current product
180 #if defined(RUN_MULTI_PROCESS_TEST)
181 namespace {
182 // use file sync diff process information
waitForStep(int step,int retryTimes)183 bool waitForStep(int step, int retryTimes)
184 {
185 std::this_thread::sleep_for(std::chrono::milliseconds(1));
186 while (retryTimes >= 0 && !OS::CheckPathExistence(g_testDir + "/LOCK_step_" + std::to_string(step))) {
187 retryTimes = retryTimes - 1; // wait 10ms one times
188 std::this_thread::sleep_for(std::chrono::milliseconds(10)); // once 10 ms
189 }
190 return (retryTimes > 0);
191 }
192
createStepFlag(int step)193 void createStepFlag(int step)
194 {
195 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + "/LOCK_step_" + std::to_string(step)), E_OK);
196 }
197 }
198
199 /**
200 * @tc.name: DiffProcessLockFile
201 * @tc.desc: Test different process repeat lock same file.
202 * @tc.type: FUNC
203 * @tc.require: AR000FN6G9
204 * @tc.author: sunpeng
205 */
206 HWTEST_F(DistributedDBCommonTest, DiffProcessLockFile, TestSize.Level1)
207 {
208 OS::FileHandle fd;
209 EXPECT_EQ(OS::OpenFile(g_testDir + DBConstant::DB_LOCK_POSTFIX, fd), E_OK);
210 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
211 sleep(1);
212 LOGI("begin fork new process!!");
213 pid_t pid = fork();
214 ASSERT_TRUE(pid >= 0);
215 if (pid < 0) {
216 return;
217 }
218 else if (pid == 0) {
219 LOGI("child process begin!");
220 OS::FileHandle ChildFd;
221 EXPECT_EQ(OS::OpenFile(g_testDir + DBConstant::DB_LOCK_POSTFIX, ChildFd), E_OK);
222 ASSERT_TRUE(waitForStep(1, 10));
223 EXPECT_EQ(OS::FileLock(ChildFd, false), -E_BUSY);
224 createStepFlag(2);
225 EXPECT_EQ(OS::CloseFile(ChildFd), E_OK);
226 exit(0);
227 } else {
228 LOGI("main process begin!");
229 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
230 createStepFlag(1);
231
232 ASSERT_TRUE(waitForStep(2, 100));
233 EXPECT_EQ(OS::CloseFile(fd), E_OK); // fd close, lock invalid
234 }
235 }
236
237 /**
238 * @tc.name: DiffProcessLockFileBlocked
239 * @tc.desc: Test different process repeat lock same file.
240 * @tc.type: FUNC
241 * @tc.require: AR000FN6G9
242 * @tc.author: sunpeng
243 */
244 HWTEST_F(DistributedDBCommonTest, DiffProcessLockFileBlocked, TestSize.Level1)
245 {
246 EXPECT_EQ(OS::CreateFileByFileName(g_testDir + DBConstant::DB_LOCK_POSTFIX), E_OK);
247 OS::FileHandle fd;
248 EXPECT_EQ(OS::OpenFile(g_testDir + DBConstant::DB_LOCK_POSTFIX, fd), E_OK);
249 EXPECT_EQ(OS::FileLock(fd, true), E_OK);
250 sleep(1);
251 LOGI("begin fork new process!!");
252 int count = 10; // wait 10 times 10 ms for block wait
253 pid_t pid = fork();
254 ASSERT_TRUE(pid >= 0);
255 if (pid < 0) {
256 return;
257 }
258 else if (pid == 0) {
259 LOGI("child process begin!");
260 EXPECT_FALSE(OS::CheckPathExistence(g_testDir + "/LOCK_step_1"));
261 OS::FileHandle ChildFd;
262 EXPECT_EQ(OS::OpenFile(g_testDir + DBConstant::DB_LOCK_POSTFIX, ChildFd), E_OK);
263 EXPECT_EQ(OS::FileLock(ChildFd, true), E_OK);
264 createStepFlag(1);
265 EXPECT_EQ(OS::FileUnlock(ChildFd), E_OK);
266 LOGI("child process finish!");
267 exit(0);
268 } else {
269 LOGI("main process begin!");
270 while (count--) {
271 LOGI("main process waiting!");
272 std::this_thread::sleep_for(std::chrono::milliseconds(10)); // once 10 ms
273 }
274 ASSERT_FALSE(waitForStep(1, 10));
275 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
276 ASSERT_TRUE(waitForStep(1, 10));
277 }
278 }
279
280 /**
281 * @tc.name: DiffProcessGetDBBlocked
282 * @tc.desc: Test block other process get kvstore when db locked.
283 * @tc.type: FUNC
284 * @tc.require: AR000CQDV7
285 * @tc.author: sunpeng
286 */
287 HWTEST_F(DistributedDBCommonTest, DiffProcessGetDBBlocked, TestSize.Level1)
288 {
289 std::string storeId = "DiffProcessGetDBBlocked";
290 std::string origId = USER_ID + "-" + APP_ID + "-" + storeId;
291 std::string identifier = DBCommon::TransferHashString(origId);
292 std::string hexDir = DBCommon::TransferStringToHex(identifier);
293 std::string lockFile = g_testDir + "/" + hexDir + DBConstant::DB_LOCK_POSTFIX;
294 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/" + hexDir), E_OK);
295 EXPECT_EQ(OS::CreateFileByFileName(lockFile), E_OK);
296 LOGI("Create lock file[%s]", lockFile.c_str());
297
298 LOGI("begin fork new process!!");
299 pid_t pid = fork();
300 OS::FileHandle fd;
301 ASSERT_TRUE(pid >= 0);
302 if (pid == 0) {
303 LOGI("child process begin!");
304 ASSERT_TRUE(waitForStep(1, 10));
305 KvStoreNbDelegate::Option option = {true, false, false};
306 option.isNeedIntegrityCheck = true;
307 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
308 EXPECT_TRUE(g_kvDelegateStatus == BUSY);
309 ASSERT_TRUE(g_kvNbDelegatePtr == nullptr);
310 createStepFlag(2);
311 exit(0);
312 } else {
313 LOGI("main process begin!");
314 EXPECT_EQ(OS::OpenFile(lockFile, fd), E_OK);
315 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
316 createStepFlag(1);
317 }
318
319 // Prevent the child process from not being completed, the main process ends to clean up resources
320 EXPECT_TRUE(waitForStep(2, 1000));
321 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
322 }
323
324 /**
325 * @tc.name: DiffProcessDeleteDBBlocked
326 * @tc.desc: Test block other process delete kvstore when db locked.
327 * @tc.type: FUNC
328 * @tc.require: AR000CQDV7
329 * @tc.author: sunpeng
330 */
331 HWTEST_F(DistributedDBCommonTest, DiffProcessDeleteDBBlocked, TestSize.Level1)
332 {
333 std::string storeId = "DiffProcessDeleteDBBlocked";
334 std::string origId = USER_ID + "-" + APP_ID + "-" + storeId;
335 std::string identifier = DBCommon::TransferHashString(origId);
336 std::string hexDir = DBCommon::TransferStringToHex(identifier);
337 std::string lockFile = g_testDir + "/" + hexDir + DBConstant::DB_LOCK_POSTFIX;
338 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/" + hexDir), E_OK);
339 EXPECT_EQ(OS::CreateFileByFileName(lockFile), E_OK);
340 LOGI("Create lock file[%s]", lockFile.c_str());
341
342 KvStoreNbDelegate::Option option = {true, false, false};
343 option.isNeedIntegrityCheck = true;
344 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
345 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
346 EXPECT_TRUE(g_kvDelegateStatus == OK);
347
348 LOGI("begin fork new process!!");
349 pid_t pid = fork();
350 OS::FileHandle fd;
351 ASSERT_TRUE(pid >= 0);
352 if (pid == 0) {
353 LOGI("child process begin!");
354 ASSERT_TRUE(waitForStep(1, 10));
355 EXPECT_EQ(g_mgr.DeleteKvStore(storeId), BUSY);
356 createStepFlag(2);
357 exit(0);
358 } else {
359 LOGI("main process begin!");
360 EXPECT_EQ(OS::OpenFile(lockFile, fd), E_OK);
361 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
362 createStepFlag(1);
363 }
364
365 // Prevent the child process from not being completed, the main process ends to clean up resources
366 EXPECT_TRUE(waitForStep(2, 1000));
367 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
368 g_mgr.CloseKvStore(g_kvNbDelegatePtr);
369 }
370
371 /**
372 * @tc.name: DiffProcessGetDBBlocked001
373 * @tc.desc: Test block other process get kvstore when db locked.
374 * @tc.type: FUNC
375 * @tc.require: AR000CQDV7
376 * @tc.author: sunpeng
377 */
378 HWTEST_F(DistributedDBCommonTest, DiffProcessGetDBBlocked001, TestSize.Level1)
379 {
380 std::string storeId = "DiffProcessGetDBBlocked001";
381 std::string origId = USER_ID + "-" + APP_ID + "-" + storeId;
382 std::string identifier = DBCommon::TransferHashString(origId);
383 std::string hexDir = DBCommon::TransferStringToHex(identifier);
384 std::string lockFile = g_testDir + "/" + hexDir + DBConstant::DB_LOCK_POSTFIX;
385 EXPECT_EQ(DBCommon::CreateDirectory(g_testDir + "/" + hexDir), E_OK);
386 EXPECT_EQ(OS::CreateFileByFileName(lockFile), E_OK);
387 LOGI("Create lock file[%s]", lockFile.c_str());
388
389 LOGI("begin fork new process!!");
390 pid_t pid = fork();
391 OS::FileHandle fd;
392 ASSERT_TRUE(pid >= 0);
393 if (pid == 0) {
394 LOGI("child process begin!");
395 ASSERT_TRUE(waitForStep(1, 10));
396 KvStoreNbDelegate::Option option = {true, false, false};
397 option.isNeedIntegrityCheck = true;
398 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
399 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
400 EXPECT_TRUE(g_kvDelegateStatus == OK);
401 createStepFlag(2);
402 exit(0);
403 } else {
404 LOGI("main process begin!");
405 EXPECT_EQ(OS::OpenFile(lockFile, fd), E_OK);
406 EXPECT_EQ(OS::FileLock(fd, false), E_OK);
407 createStepFlag(1);
408 }
409 ASSERT_TRUE(waitForStep(1, 100));
410
411 EXPECT_EQ(OS::FileUnlock(fd), E_OK);
412
413 ASSERT_TRUE(waitForStep(2, 100));
414 }
415
416 /**
417 * @tc.name: DiffProcessGetDB
418 * @tc.desc: Test block other process get kvstore.
419 * @tc.type: FUNC
420 * @tc.require: AR000CQDV7
421 * @tc.author: sunpeng
422 */
423 HWTEST_F(DistributedDBCommonTest, DiffProcessGetDB, TestSize.Level1)
424 {
425 std::string storeId = "DiffProcessGetDB";
426 KvStoreNbDelegate::Option option = {true, false, false};
427 option.isNeedIntegrityCheck = true;
428 LOGI("begin fork new process!!");
429 pid_t pid = fork();
430 ASSERT_TRUE(pid >= 0);
431 if (pid == 0) {
432 LOGI("child process begin!");
433 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
434 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
435 EXPECT_TRUE(g_kvDelegateStatus == OK);
436 createStepFlag(2);
437 EXPECT_TRUE(waitForStep(1, 1000));
438 exit(0);
439 } else {
440 LOGI("main process begin!");
441 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
442 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
443 EXPECT_TRUE(g_kvDelegateStatus == OK);
444 createStepFlag(1);
445 }
446 EXPECT_TRUE(waitForStep(2, 100));
447 // Prevent the child process from not being completed, the main process ends to clean up resources
448 g_mgr.CloseKvStore(g_kvNbDelegatePtr);
449 }
450
451 /**
452 * @tc.name: DiffProcessDeleteDB
453 * @tc.desc: Test block other process delete kvstore.
454 * @tc.type: FUNC
455 * @tc.require: AR000CQDV7
456 * @tc.author: sunpeng
457 */
458 HWTEST_F(DistributedDBCommonTest, DiffProcessDeleteDB, TestSize.Level1)
459 {
460 std::string storeId = "DiffProcessGetDB";
461 KvStoreNbDelegate::Option option = {true, false, false};
462 option.isNeedIntegrityCheck = true;
463 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
464 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
465 EXPECT_TRUE(g_kvDelegateStatus == OK);
466 g_mgr.CloseKvStore(g_kvNbDelegatePtr);
467 LOGI("begin fork new process!!");
468 pid_t pid = fork();
469 ASSERT_TRUE(pid >= 0);
470 if (pid == 0) {
471 LOGI("child process begin!");
472 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
473 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
474 EXPECT_TRUE(g_kvDelegateStatus == OK);
475 createStepFlag(2);
476 EXPECT_TRUE(waitForStep(1, 1000));
477 exit(0);
478 } else {
479 LOGI("main process begin!");
480 g_mgr.DeleteKvStore(storeId);
481 createStepFlag(1);
482 }
483 EXPECT_TRUE(waitForStep(2, 100));
484
485 // Prevent the child process from not being completed, the main process ends to clean up resources
486 EXPECT_TRUE(waitForStep(1, 100));
487 }
488
489 /**
490 * @tc.name: DiffProcessGetAndDeleteDB
491 * @tc.desc: Test block other process delete kvstore.
492 * @tc.type: FUNC
493 * @tc.require: AR000CQDV7
494 * @tc.author: sunpeng
495 */
496 HWTEST_F(DistributedDBCommonTest, DiffProcessGetAndDeleteDB, TestSize.Level1)
497 {
498 std::string storeId = "DiffProcessGetAndDeleteDB";
499 KvStoreNbDelegate::Option option = {true, false, false};
500 option.isNeedIntegrityCheck = true;
501 g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback);
502 ASSERT_TRUE(g_kvNbDelegatePtr != nullptr);
503 EXPECT_TRUE(g_kvDelegateStatus == OK);
504 g_mgr.CloseKvStore(g_kvNbDelegatePtr);
505 LOGI("begin fork new process!!");
506 pid_t pid = fork();
507 ASSERT_TRUE(pid >= 0);
508 if (pid == 0) {
509 LOGI("child process begin!");
510 g_mgr.DeleteKvStore(storeId); // one process OK, one process NOT_FOUND
511 createStepFlag(2);
512 EXPECT_TRUE(waitForStep(1, 1000));
513 exit(0);
514 } else {
515 LOGI("main process begin!");
516 g_mgr.DeleteKvStore(storeId);
517 createStepFlag(1);
518 }
519 EXPECT_TRUE(waitForStep(2, 100));
520
521 // Prevent the child process from not being completed, the main process ends to clean up resources
522 EXPECT_TRUE(waitForStep(1, 1000));
523 }
524 #endif
525 #endif
526