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 <chrono> 17 18#include "finite_state_machine.h" 19 20#include "mock_thread_handler.h" 21 22namespace OHOS { 23namespace UserIam { 24namespace FaceAuth { 25using namespace testing; 26using namespace testing::ext; 27 28enum State : uint32_t { 29 STATE_INIT, 30 STATE_VERIFY_STARING, 31 STATE_COLLECT_STARING, 32 STATE_AUTH_PROCESSING, 33 STATE_VERIFY_STOPPING, 34 STATE_COLLECT_STOPPING, 35 STATE_END 36}; 37 38enum Event : uint32_t { 39 EVENT_START_AUTH, 40 EVENT_VERIFY_STARTED, 41 EVENT_COLLECT_STARTED, 42 EVENT_AUTH_RESULT_GET, 43 EVENT_VERIFY_STOPPED, 44 EVENT_COLLECT_STOP, 45 EVENT_USER_CANCEL, 46 EVENT_TIME_OUT, 47}; 48 49class StateMachineTest : public testing::Test { 50public: 51 static void SetUpTestCase(); 52 53 static void TearDownTestCase(); 54 55 void SetUp() override; 56 57 void TearDown() override; 58}; 59 60void StateMachineTest::SetUpTestCase() 61{ 62} 63 64void StateMachineTest::TearDownTestCase() 65{ 66} 67 68void StateMachineTest::SetUp() 69{ 70 ThreadHandler::GetSingleThreadInstance()->EnsureTask(nullptr); 71} 72 73void StateMachineTest::TearDown() 74{ 75 ThreadHandler::GetSingleThreadInstance()->EnsureTask(nullptr); 76} 77 78HWTEST_F(StateMachineTest, MachineCreateSelfReturn, TestSize.Level0) 79{ 80 auto handler = ThreadHandler::GetSingleThreadInstance(); 81 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine0", STATE_INIT); 82 EXPECT_NE(machineBuilder, nullptr); 83 84 auto ret1 = machineBuilder->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING); 85 EXPECT_NE(ret1, nullptr); 86 87 auto ret2 = ret1->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING); 88 EXPECT_EQ(ret2, ret1); 89} 90 91HWTEST_F(StateMachineTest, MachineCreateOnlyBuildOnce, TestSize.Level0) 92{ 93 auto handler = ThreadHandler::GetSingleThreadInstance(); 94 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine1", STATE_INIT); 95 EXPECT_NE(machineBuilder, nullptr); 96 97 machineBuilder->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING) 98 ->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING); 99 100 auto first = machineBuilder->Build(); 101 EXPECT_NE(first, nullptr); 102 103 auto second = machineBuilder->Build(); 104 EXPECT_EQ(second, nullptr); 105} 106 107HWTEST_F(StateMachineTest, MachineCreateCheckTransition, TestSize.Level0) 108{ 109 auto handler = ThreadHandler::GetSingleThreadInstance(); 110 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine2", STATE_INIT); 111 EXPECT_NE(machineBuilder, nullptr); 112 113 machineBuilder->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING) 114 ->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_COLLECT_STARING); 115 116 auto machine = machineBuilder->Build(); 117 EXPECT_EQ(machine, nullptr); 118} 119 120HWTEST_F(StateMachineTest, MachineCreateInitialState, TestSize.Level0) 121{ 122 auto handler = ThreadHandler::GetSingleThreadInstance(); 123 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine3", STATE_COLLECT_STOPPING); 124 ASSERT_NE(machineBuilder, nullptr); 125 126 machineBuilder->MakeTransition(STATE_COLLECT_STOPPING, EVENT_START_AUTH, STATE_VERIFY_STARING); 127 auto machine = machineBuilder->Build(); 128 ASSERT_NE(machine, nullptr); 129 EXPECT_EQ(machine->GetCurrentState(), STATE_COLLECT_STOPPING); 130} 131 132HWTEST_F(StateMachineTest, MachineCreateNameCheck, TestSize.Level0) 133{ 134 auto handler = ThreadHandler::GetSingleThreadInstance(); 135 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine4", STATE_COLLECT_STOPPING); 136 ASSERT_NE(machineBuilder, nullptr); 137 138 machineBuilder->MakeTransition(STATE_COLLECT_STOPPING, EVENT_START_AUTH, STATE_VERIFY_STARING); 139 auto machine = machineBuilder->Build(); 140 ASSERT_NE(machine, nullptr); 141 EXPECT_EQ(machine->GetMachineName(), "testMachine4"); 142} 143 144HWTEST_F(StateMachineTest, MachineScheduleStepIn, TestSize.Level0) 145{ 146 auto handler = ThreadHandler::GetSingleThreadInstance(); 147 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine5", STATE_INIT); 148 ASSERT_NE(machineBuilder, nullptr); 149 150 machineBuilder->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING) 151 ->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING); 152 153 auto machine = machineBuilder->Build(); 154 ASSERT_NE(machine, nullptr); 155 EXPECT_EQ(machine->GetCurrentState(), STATE_INIT); 156 157 machine->Schedule(EVENT_START_AUTH); 158 EXPECT_EQ(machine->EnsureCurrentState(), STATE_VERIFY_STARING); 159 machine->Schedule(EVENT_VERIFY_STARTED); 160 EXPECT_EQ(machine->EnsureCurrentState(), STATE_COLLECT_STARING); 161 machine->Schedule(EVENT_VERIFY_STARTED); 162 EXPECT_EQ(machine->EnsureCurrentState(), STATE_COLLECT_STARING); 163} 164 165HWTEST_F(StateMachineTest, MachineScheduleWithAction, TestSize.Level0) 166{ 167 auto handler = ThreadHandler::GetSingleThreadInstance(); 168 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine6", STATE_INIT); 169 ASSERT_NE(machineBuilder, nullptr); 170 171 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action1; 172 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action2; 173 { 174 auto init = [](FiniteStateMachine &machine) { return machine.GetCurrentState() == STATE_INIT; }; 175 auto verify = [](FiniteStateMachine &machine) { return machine.GetCurrentState() == EVENT_VERIFY_STARTED; }; 176 InSequence s; 177 EXPECT_CALL(action1, Call(Truly(init), EVENT_START_AUTH)).Times(Exactly(1)); 178 EXPECT_CALL(action2, Call(Truly(verify), EVENT_VERIFY_STARTED)).Times(Exactly(1)); 179 } 180 181 machineBuilder 182 ->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING, 183 [&action1](FiniteStateMachine &machine, uint32_t event) { action1.Call(machine, event); }) 184 ->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING, 185 [&action2](FiniteStateMachine &machine, uint32_t event) { action2.Call(machine, event); }); 186 187 auto machine = machineBuilder->Build(); 188 ASSERT_NE(machine, nullptr); 189 EXPECT_EQ(machine->EnsureCurrentState(), STATE_INIT); 190 191 machine->Schedule(EVENT_START_AUTH); 192 EXPECT_EQ(machine->EnsureCurrentState(), STATE_VERIFY_STARING); 193 machine->Schedule(EVENT_VERIFY_STARTED); 194 EXPECT_EQ(machine->EnsureCurrentState(), STATE_COLLECT_STARING); 195 machine->Schedule(EVENT_VERIFY_STARTED); 196 EXPECT_EQ(machine->EnsureCurrentState(), STATE_COLLECT_STARING); 197} 198 199HWTEST_F(StateMachineTest, MachineScheduleWithComplexActionDirectly, TestSize.Level0) 200{ 201 auto handler = MockThreadHandler::InvokeDirectly(); 202 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine7", STATE_INIT); 203 ASSERT_NE(machineBuilder, nullptr); 204 205 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action1; 206 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action2; 207 { 208 auto init = [](FiniteStateMachine &machine) { return machine.GetCurrentState() == STATE_INIT; }; 209 auto verify = [](FiniteStateMachine &machine) { return machine.GetCurrentState() == EVENT_VERIFY_STARTED; }; 210 211 InSequence s; 212 EXPECT_CALL(action1, Call(Truly(init), EVENT_START_AUTH)).Times(Exactly(1)); 213 EXPECT_CALL(action2, Call(Truly(verify), EVENT_VERIFY_STARTED)).Times(Exactly(1)); 214 } 215 216 machineBuilder 217 ->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING, 218 [&action1](FiniteStateMachine &machine, uint32_t event) { 219 action1.Call(machine, event); 220 machine.Schedule(EVENT_VERIFY_STARTED); 221 }) 222 ->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING, 223 [&action2](FiniteStateMachine &machine, uint32_t event) { 224 action2.Call(machine, event); 225 machine.Schedule(EVENT_COLLECT_STARTED); 226 }) 227 ->MakeTransition(STATE_COLLECT_STARING, EVENT_COLLECT_STARTED, STATE_AUTH_PROCESSING, nullptr); 228 229 auto machine = machineBuilder->Build(); 230 ASSERT_NE(machine, nullptr); 231 EXPECT_EQ(machine->EnsureCurrentState(), STATE_INIT); 232 233 machine->Schedule(EVENT_START_AUTH); 234 EXPECT_EQ(machine->EnsureCurrentState(), STATE_AUTH_PROCESSING); 235} 236 237HWTEST_F(StateMachineTest, MachineScheduleWithComplexActionBackGround, TestSize.Level0) 238{ 239 auto handler = ThreadHandler::GetSingleThreadInstance(); 240 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine8", STATE_INIT); 241 ASSERT_NE(machineBuilder, nullptr); 242 243 machineBuilder 244 ->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING, 245 [](FiniteStateMachine &machine, [[maybe_unused]] uint32_t event) { 246 machine.Schedule(EVENT_VERIFY_STARTED); 247 machine.Schedule(EVENT_COLLECT_STARTED); 248 machine.Schedule(EVENT_USER_CANCEL); 249 }) 250 ->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING, nullptr) 251 ->MakeTransition(STATE_COLLECT_STARING, EVENT_COLLECT_STARTED, STATE_AUTH_PROCESSING, nullptr) 252 ->MakeTransition(STATE_AUTH_PROCESSING, EVENT_USER_CANCEL, STATE_END, nullptr); 253 auto machine = machineBuilder->Build(); 254 ASSERT_NE(machine, nullptr); 255 EXPECT_EQ(machine->EnsureCurrentState(), STATE_INIT); 256 257 machine->Schedule(EVENT_START_AUTH); 258 EXPECT_EQ(machine->EnsureCurrentState(), STATE_END); 259} 260 261HWTEST_F(StateMachineTest, MachineScheduleDeadlock, TestSize.Level0) 262{ 263 auto handler = ThreadHandler::GetSingleThreadInstance(); 264 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine9", STATE_INIT); 265 ASSERT_NE(machineBuilder, nullptr); 266 machineBuilder->MakeTransition(STATE_INIT, STATE_INIT, STATE_INIT, [](FiniteStateMachine &machine, uint32_t event) { 267 machine.Schedule(STATE_INIT); 268 machine.Schedule(STATE_INIT); 269 machine.Schedule(STATE_INIT); 270 }); 271 auto machine = machineBuilder->Build(); 272 ASSERT_NE(machine, nullptr); 273 EXPECT_EQ(machine->EnsureCurrentState(), STATE_INIT); 274 275 machine->Schedule(EVENT_START_AUTH); 276 EXPECT_EQ(machine->EnsureCurrentState(), STATE_INIT); 277} 278 279HWTEST_F(StateMachineTest, MachineScheduleContinues, TestSize.Level0) 280{ 281 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action; 282 EXPECT_CALL(action, Call(_, STATE_INIT)).Times(Exactly(3)); 283 auto handler = ThreadHandler::GetSingleThreadInstance(); 284 { 285 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine10", STATE_INIT); 286 ASSERT_NE(machineBuilder, nullptr); 287 machineBuilder->MakeTransition(STATE_INIT, STATE_INIT, STATE_INIT, 288 [&action](FiniteStateMachine &machine, [[maybe_unused]] uint32_t event) { 289 action.Call(machine, STATE_INIT); 290 }); 291 auto machine = machineBuilder->Build(); 292 ASSERT_NE(machine, nullptr); 293 machine->Schedule(STATE_INIT); 294 machine->Schedule(STATE_INIT); 295 machine->Schedule(STATE_INIT); 296 handler->EnsureTask(nullptr); 297 } 298} 299 300HWTEST_F(StateMachineTest, MachineScheduleExpireNodeTimeout, TestSize.Level0) 301{ 302 auto handler = ThreadHandler::GetSingleThreadInstance(); 303 304 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action; 305 EXPECT_CALL(action, Call(_, STATE_INIT)).Times(Exactly(5)); 306 { 307 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine11", STATE_INIT); 308 ASSERT_NE(machineBuilder, nullptr); 309 machineBuilder->MakeTransition(STATE_INIT, STATE_INIT, STATE_INIT, 310 [&action](FiniteStateMachine &machine, [[maybe_unused]] uint32_t event) { 311 std::this_thread::sleep_for(std::chrono::milliseconds(200)); 312 action.Call(machine, STATE_INIT); 313 }); 314 auto machine = machineBuilder->Build(); 315 ASSERT_NE(machine, nullptr); 316 317 machine->SetThreadHandler(handler); 318 handler->EnsureTask(nullptr); 319 machine->Schedule(STATE_INIT); 320 machine->Schedule(STATE_INIT); 321 machine->Schedule(STATE_INIT); 322 machine->Schedule(STATE_INIT); 323 machine->Schedule(STATE_INIT); 324 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 325 machine = nullptr; 326 handler->EnsureTask(nullptr); 327 } 328} 329 330HWTEST_F(StateMachineTest, MachineScheduleExpireNodeExpire, TestSize.Level0) 331{ 332 auto handler = ThreadHandler::GetSingleThreadInstance(); 333 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action; 334 EXPECT_CALL(action, Call(_, STATE_INIT)).Times(Exactly(0)); 335 { 336 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine12", STATE_INIT); 337 ASSERT_NE(machineBuilder, nullptr); 338 machineBuilder->MakeTransition(STATE_INIT, STATE_INIT, STATE_INIT, 339 [&action](FiniteStateMachine &machine, [[maybe_unused]] uint32_t event) { 340 action.Call(machine, STATE_INIT); 341 }); 342 auto machine = machineBuilder->Build(); 343 ASSERT_NE(machine, nullptr); 344 handler->PostTask([]() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); }); 345 machine->Schedule(STATE_INIT); 346 machine->Schedule(STATE_INIT); 347 machine->Schedule(STATE_INIT); 348 machine->Schedule(STATE_INIT); 349 machine->Schedule(STATE_INIT); 350 machine = nullptr; 351 } 352 handler->EnsureTask(nullptr); 353} 354 355static void GetTestMachine(std::shared_ptr<FiniteStateMachine> &machine, 356 MockFunction<void(FiniteStateMachine &machine, uint32_t event)> &action, 357 MockFunction<void(FiniteStateMachine &machine, uint32_t event)> &enter, 358 MockFunction<void(FiniteStateMachine &machine, uint32_t event)> &leave) 359{ 360 auto machineBuilder = FiniteStateMachine::Builder::New("testMachine13", STATE_INIT); 361 ASSERT_NE(machineBuilder, nullptr); 362 363 machineBuilder->MakeTransition(STATE_INIT, EVENT_START_AUTH, STATE_VERIFY_STARING, 364 [&action](FiniteStateMachine &machine, uint32_t event) { 365 action.Call(machine, event); 366 machine.Schedule(EVENT_VERIFY_STARTED); 367 machine.Schedule(EVENT_COLLECT_STARTED); 368 }); 369 machineBuilder->MakeTransition(STATE_VERIFY_STARING, EVENT_VERIFY_STARTED, STATE_COLLECT_STARING, 370 [&action](FiniteStateMachine &machine, uint32_t event) { action.Call(machine, event); }); 371 machineBuilder->MakeTransition(STATE_COLLECT_STARING, EVENT_COLLECT_STARTED, STATE_AUTH_PROCESSING, 372 [&action](FiniteStateMachine &machine, uint32_t event) { action.Call(machine, event); }); 373 machineBuilder->MakeTransition(STATE_AUTH_PROCESSING, EVENT_USER_CANCEL, STATE_END, 374 [&action](FiniteStateMachine &machine, uint32_t event) { action.Call(machine, event); }); 375 376 machineBuilder->MakeOnStateEnter(STATE_INIT, 377 [&enter](FiniteStateMachine &machine, uint32_t event) { enter.Call(machine, event); }); 378 machineBuilder->MakeOnStateLeave(STATE_INIT, 379 [&leave](FiniteStateMachine &machine, uint32_t event) { leave.Call(machine, event); }); 380 381 machineBuilder->MakeOnStateEnter(STATE_VERIFY_STARING, 382 [&enter](FiniteStateMachine &machine, uint32_t event) { enter.Call(machine, event); }); 383 machineBuilder->MakeOnStateLeave(STATE_VERIFY_STARING, 384 [&leave](FiniteStateMachine &machine, uint32_t event) { leave.Call(machine, event); }); 385 386 machineBuilder->MakeOnStateEnter(STATE_COLLECT_STARING, 387 [&enter](FiniteStateMachine &machine, uint32_t event) { enter.Call(machine, event); }); 388 machineBuilder->MakeOnStateLeave(STATE_COLLECT_STARING, 389 [&leave](FiniteStateMachine &machine, uint32_t event) { leave.Call(machine, event); }); 390 391 machineBuilder->MakeOnStateEnter(STATE_AUTH_PROCESSING, 392 [&enter](FiniteStateMachine &machine, uint32_t event) { enter.Call(machine, event); }); 393 machineBuilder->MakeOnStateLeave(STATE_AUTH_PROCESSING, 394 [&leave](FiniteStateMachine &machine, uint32_t event) { leave.Call(machine, event); }); 395 396 machineBuilder->MakeOnStateEnter(STATE_END, 397 [&enter](FiniteStateMachine &machine, uint32_t event) { enter.Call(machine, event); }); 398 399 machine = machineBuilder->Build(); 400} 401 402HWTEST_F(StateMachineTest, MachineScheduleEnterAndLeave, TestSize.Level0) 403{ 404 auto handler = ThreadHandler::GetSingleThreadInstance(); 405 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> action; 406 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> enter; 407 MockFunction<void(FiniteStateMachine & machine, uint32_t event)> leave; 408 409 InSequence s; 410 EXPECT_CALL(action, Call(_, EVENT_START_AUTH)); 411 EXPECT_CALL(leave, Call(_, STATE_INIT)); 412 EXPECT_CALL(enter, Call(_, STATE_VERIFY_STARING)); 413 414 EXPECT_CALL(action, Call(_, EVENT_VERIFY_STARTED)); 415 EXPECT_CALL(leave, Call(_, STATE_VERIFY_STARING)); 416 EXPECT_CALL(enter, Call(_, STATE_COLLECT_STARING)); 417 418 EXPECT_CALL(action, Call(_, EVENT_COLLECT_STARTED)); 419 EXPECT_CALL(leave, Call(_, STATE_COLLECT_STARING)); 420 EXPECT_CALL(enter, Call(_, STATE_AUTH_PROCESSING)); 421 422 EXPECT_CALL(action, Call(_, EVENT_USER_CANCEL)); 423 EXPECT_CALL(leave, Call(_, STATE_AUTH_PROCESSING)); 424 EXPECT_CALL(enter, Call(_, STATE_END)); 425 426 std::shared_ptr<FiniteStateMachine> machine; 427 GetTestMachine(machine, action, enter, leave); 428 ASSERT_NE(machine, nullptr); 429 430 machine->SetThreadHandler(handler); 431 handler->EnsureTask(nullptr); 432 machine->Schedule(EVENT_START_AUTH); 433 handler->EnsureTask(nullptr); 434 machine->Schedule(EVENT_USER_CANCEL); 435 EXPECT_EQ(STATE_END, machine->EnsureCurrentState()); 436 437 handler->EnsureTask(nullptr); 438} 439} // namespace FaceAuth 440} // namespace UserIam 441} // namespace OHOS