1 // Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <util/state_model.h>
10 
11 #include <gtest/gtest.h>
12 
13 using namespace std;
14 using namespace isc;
15 using namespace isc::util;
16 
17 namespace {
18 
19 /// @brief Test derivation of StateModel for exercising state model mechanics.
20 ///
21 /// This class facilitates testing by making non-public methods accessible so
22 /// they can be invoked directly in test routines.  It implements a very
23 /// rudimentary state model, sufficient to test the state model mechanics
24 /// supplied by the base class.
25 class StateModelTest : public StateModel, public testing::Test {
26 public:
27 
28     ///@brief StateModelTest states
29     ///@brief Fake state used for handler mapping tests.
30     static const int DUMMY_ST = SM_DERIVED_STATE_MIN + 1;
31 
32     ///@brief Starting state for the test state model.
33     static const int READY_ST = SM_DERIVED_STATE_MIN + 2;
34 
35     ///@brief State which simulates doing asynchronous work.
36     static const int DO_WORK_ST = SM_DERIVED_STATE_MIN + 3;
37 
38     ///@brief State which finishes off processing.
39     static const int DONE_ST = SM_DERIVED_STATE_MIN + 4;
40 
41     ///@brief State in which model is always paused.
42     static const int PAUSE_ALWAYS_ST = SM_DERIVED_STATE_MIN + 5;
43 
44     ///@brief State in which model is paused at most once.
45     static const int PAUSE_ONCE_ST = SM_DERIVED_STATE_MIN + 6;
46 
47     // StateModelTest events
48     ///@brief Event used to trigger initiation of asynchronous work.
49     static const int WORK_START_EVT = SM_DERIVED_EVENT_MIN + 1;
50 
51     ///@brief Event issued when the asynchronous work "completes".
52     static const int WORK_DONE_EVT = SM_DERIVED_EVENT_MIN + 2;
53 
54     ///@brief Event issued when all the work is done.
55     static const int ALL_DONE_EVT = SM_DERIVED_EVENT_MIN + 3;
56 
57     ///@brief Event used to trigger an attempt to transition to bad state
58     static const int FORCE_UNDEFINED_ST_EVT = SM_DERIVED_EVENT_MIN + 4;
59 
60     ///@brief Event used to trigger an attempt to transition to bad state
61     static const int SIMULATE_ERROR_EVT = SM_DERIVED_EVENT_MIN + 5;
62 
63     ///@brief Event used to indicate that state machine is unpaused.
64     static const int UNPAUSED_EVT = SM_DERIVED_EVENT_MIN + 6;
65 
66     /// @brief Constructor
67     ///
68     /// Parameters match those needed by StateModel.
StateModelTest()69     StateModelTest() : dummy_called_(false), work_completed_(false),
70                        failure_explanation_("") {
71     }
72     /// @brief Destructor
~StateModelTest()73     virtual ~StateModelTest() {
74     }
75 
76     /// @brief Fetches the value of the dummy called flag.
getDummyCalled()77     bool getDummyCalled() {
78         return (dummy_called_);
79     }
80 
81     /// @brief StateHandler for fake state, DummyState.
82     ///
83     /// It simply sets the dummy called flag to indicate that this method
84     /// was invoked.
dummyHandler()85     void dummyHandler() {
86         dummy_called_ = true;
87     }
88 
89     /// @brief Returns the failure explanation string.
90     ///
91     /// This value is set only via onModelFailure and it stores whatever
92     /// explanation that method was passed.
getFailureExplanation()93     const std::string& getFailureExplanation() {
94         return (failure_explanation_);
95     }
96 
97     /// @brief Returns indication of whether or not the model succeeded.
98     ///
99     /// If true, this indicates that the test model executed correctly through
100     /// to completion.  The flag is only by the DONE_ST handler.
getWorkCompleted()101     bool getWorkCompleted() {
102         return (work_completed_);
103     }
104 
105     /// @brief State handler for the READY_ST.
106     ///
107     /// Serves as the starting state handler, it consumes the
108     /// START_EVT "transitioning" to the state, DO_WORK_ST and
109     /// sets the next event to WORK_START_EVT.
readyHandler()110     void readyHandler() {
111         switch(getNextEvent()) {
112         case START_EVT:
113             transition(DO_WORK_ST, WORK_START_EVT);
114             break;
115         default:
116             // its bogus
117             isc_throw(StateModelError, "readyHandler:invalid event: "
118                       << getContextStr());
119         }
120     }
121 
122     /// @brief State handler for the DO_WORK_ST.
123     ///
124     /// Simulates a state that starts some form of asynchronous work.
125     /// When next event is WORK_START_EVT it sets the status to pending
126     /// and signals the state model must "wait" for an event by setting
127     /// next event to NOP_EVT.
128     ///
129     /// When next event is IO_COMPLETED_EVT, it transitions to the state,
130     /// DONE_ST, and sets the next event to WORK_DONE_EVT.
doWorkHandler()131     void doWorkHandler() {
132         switch(getNextEvent()) {
133         case WORK_START_EVT:
134             postNextEvent(NOP_EVT);
135             break;
136         case WORK_DONE_EVT:
137             work_completed_ = true;
138             transition(DONE_ST, ALL_DONE_EVT);
139             break;
140         case FORCE_UNDEFINED_ST_EVT:
141             transition(9999, ALL_DONE_EVT);
142             break;
143         case SIMULATE_ERROR_EVT:
144             throw std::logic_error("Simulated Unexpected Error");
145             break;
146         default:
147             // its bogus
148             isc_throw(StateModelError, "doWorkHandler:invalid event: "
149                       <<  getContextStr());
150         }
151     }
152 
153     /// @brief State handler for the DONE_ST.
154     ///
155     /// This is the last state in the model.  Note that it sets the
156     /// status to completed and next event to NOP_EVT.
doneWorkHandler()157     void doneWorkHandler() {
158         switch(getNextEvent()) {
159         case ALL_DONE_EVT:
160             endModel();
161             break;
162         default:
163             // its bogus
164             isc_throw(StateModelError, "doneWorkHandler:invalid event: "
165                       << getContextStr());
166         }
167     }
168 
169     /// @brief State handler for PAUSE_ALWAYS_ST and PAUSE_ONCE_ST.
pauseHandler()170     void pauseHandler() {
171         postNextEvent(NOP_EVT);
172     }
173 
174     /// @brief Construct the event dictionary.
defineEvents()175     virtual void defineEvents() {
176         // Invoke the base call implementation first.
177         StateModel::defineEvents();
178 
179         // Define our events.
180         defineEvent(WORK_START_EVT, "WORK_START_EVT");
181         defineEvent(WORK_DONE_EVT , "WORK_DONE_EVT");
182         defineEvent(ALL_DONE_EVT, "ALL_DONE_EVT");
183         defineEvent(FORCE_UNDEFINED_ST_EVT, "FORCE_UNDEFINED_ST_EVT");
184         defineEvent(SIMULATE_ERROR_EVT, "SIMULATE_ERROR_EVT");
185         defineEvent(UNPAUSED_EVT, "UNPAUSED_EVT");
186     }
187 
188     /// @brief Verify the event dictionary.
verifyEvents()189     virtual void verifyEvents() {
190         // Invoke the base call implementation first.
191         StateModel::verifyEvents();
192 
193         // Verify our events.
194         getEvent(WORK_START_EVT);
195         getEvent(WORK_DONE_EVT);
196         getEvent(ALL_DONE_EVT);
197         getEvent(FORCE_UNDEFINED_ST_EVT);
198         getEvent(SIMULATE_ERROR_EVT);
199         getEvent(UNPAUSED_EVT);
200     }
201 
202     /// @brief Construct the state dictionary.
defineStates()203     virtual void defineStates() {
204         // Invoke the base call implementation first.
205         StateModel::defineStates();
206 
207         // Define our states.
208         defineState(DUMMY_ST, "DUMMY_ST",
209                     std::bind(&StateModelTest::dummyHandler, this));
210 
211         defineState(READY_ST, "READY_ST",
212                     std::bind(&StateModelTest::readyHandler, this));
213 
214         defineState(DO_WORK_ST, "DO_WORK_ST",
215                     std::bind(&StateModelTest::doWorkHandler, this));
216 
217         defineState(DONE_ST, "DONE_ST",
218                     std::bind(&StateModelTest::doneWorkHandler, this));
219 
220         defineState(PAUSE_ALWAYS_ST, "PAUSE_ALWAYS_ST",
221                     std::bind(&StateModelTest::pauseHandler, this),
222                     STATE_PAUSE_ALWAYS);
223 
224         defineState(PAUSE_ONCE_ST, "PAUSE_ONCE_ST",
225                     std::bind(&StateModelTest::pauseHandler, this),
226                     STATE_PAUSE_ONCE);
227     }
228 
229     /// @brief Verify the state dictionary.
verifyStates()230     virtual void verifyStates() {
231         // Invoke the base call implementation first.
232         StateModel::verifyStates();
233 
234         // Verify our states.
235         getStateInternal(DUMMY_ST);
236         getStateInternal(READY_ST);
237         getStateInternal(DO_WORK_ST);
238         getStateInternal(DONE_ST);
239         getStateInternal(PAUSE_ALWAYS_ST);
240         getStateInternal(PAUSE_ONCE_ST);
241     }
242 
243     /// @brief  Manually construct the event and state dictionaries.
244     /// This allows testing without running startModel.
initDictionaries()245     void initDictionaries() {
246         ASSERT_NO_THROW(defineEvents());
247         ASSERT_NO_THROW(verifyEvents());
248         ASSERT_NO_THROW(defineStates());
249         ASSERT_NO_THROW(verifyStates());
250     }
251 
252     /// @brief Tests the event dictionary entry for the given event value.
checkEvent(const int value,const std::string & label)253     bool checkEvent(const int value, const std::string& label) {
254         EventPtr event;
255         try  {
256             event = getEvent(value);
257             EXPECT_TRUE(event);
258             EXPECT_EQ(value, event->getValue());
259             EXPECT_EQ(label, event->getLabel());
260         } catch (const std::exception& ex) {
261             return false;
262         }
263 
264         return true;
265     }
266 
267     /// @brief Tests the state dictionary entry for the given state value.
checkState(const int value,const std::string & label)268     bool checkState(const int value, const std::string& label) {
269         EventPtr state;
270         try  {
271             state = getState(value);
272             EXPECT_TRUE(state);
273             EXPECT_EQ(value, state->getValue());
274             EXPECT_EQ(label, state->getLabel());
275         } catch (const std::exception& ex) {
276             return false;
277         }
278 
279         return true;
280     }
281 
282 
283     /// @brief  Handler called when the model suffers an execution error.
onModelFailure(const std::string & explanation)284     virtual void onModelFailure(const std::string& explanation) {
285         failure_explanation_ = explanation;
286     }
287 
288     /// @brief Indicator of whether or not the DUMMY_ST handler has been called.
289     bool dummy_called_;
290 
291     /// @brief Indicator of whether or not DONE_ST handler has been called.
292     bool work_completed_;
293 
294     /// @brief Stores the failure explanation
295     std::string failure_explanation_;
296 };
297 
298 // Declare them so gtest can see them.
299 const int StateModelTest::DUMMY_ST;
300 const int StateModelTest::READY_ST;
301 const int StateModelTest::DO_WORK_ST;
302 const int StateModelTest::DONE_ST;
303 const int StateModelTest::WORK_START_EVT;
304 const int StateModelTest::WORK_DONE_EVT;
305 const int StateModelTest::ALL_DONE_EVT;
306 const int StateModelTest::PAUSE_ALWAYS_ST;
307 const int StateModelTest::PAUSE_ONCE_ST;
308 
309 /// @brief Checks the fundamentals of defining and retrieving events.
TEST_F(StateModelTest,eventDefinition)310 TEST_F(StateModelTest, eventDefinition) {
311     // After construction, the event dictionary should be empty. Verify that
312     // getEvent will throw when event is not defined.
313     EXPECT_THROW(getEvent(NOP_EVT), StateModelError);
314 
315     // Verify that we can add a handler to the map.
316     ASSERT_NO_THROW(defineEvent(NOP_EVT, "NOP_EVT"));
317 
318     // Verify that we can find the event by value and its content is correct.
319     EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
320 
321     // Verify that we cannot add a duplicate.
322     ASSERT_THROW(defineEvent(NOP_EVT, "NOP_EVT"), StateModelError);
323 
324     // Verify that we can still find the event.
325     EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
326 }
327 
328 /// @brief Tests event dictionary construction and verification.
TEST_F(StateModelTest,eventDictionary)329 TEST_F(StateModelTest, eventDictionary) {
330     // After construction, the event dictionary should be empty.
331     // Make sure that verifyEvents() throws.
332     EXPECT_THROW(verifyEvents(), StateModelError);
333 
334     // Construct the dictionary and verify it.
335     EXPECT_NO_THROW(defineEvents());
336     EXPECT_NO_THROW(verifyEvents());
337 
338     // Verify base class events are defined.
339     EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
340     EXPECT_TRUE(checkEvent(START_EVT, "START_EVT"));
341     EXPECT_TRUE(checkEvent(END_EVT, "END_EVT"));
342     EXPECT_TRUE(checkEvent(FAIL_EVT, "FAIL_EVT"));
343 
344     // Verify stub class events are defined.
345     EXPECT_TRUE(checkEvent(WORK_START_EVT, "WORK_START_EVT"));
346     EXPECT_TRUE(checkEvent(WORK_DONE_EVT, "WORK_DONE_EVT"));
347     EXPECT_TRUE(checkEvent(ALL_DONE_EVT, "ALL_DONE_EVT"));
348     EXPECT_TRUE(checkEvent(FORCE_UNDEFINED_ST_EVT, "FORCE_UNDEFINED_ST_EVT"));
349     EXPECT_TRUE(checkEvent(SIMULATE_ERROR_EVT, "SIMULATE_ERROR_EVT"));
350 
351     // Verify that undefined events are handled correctly.
352     EXPECT_THROW(getEvent(9999), StateModelError);
353     EXPECT_EQ(LabeledValueSet::UNDEFINED_LABEL, getEventLabel(9999));
354 }
355 
356 /// @brief General testing of event context accessors.
357 /// Most if not all of these are also tested as a byproduct off larger tests.
TEST_F(StateModelTest,eventContextAccessors)358 TEST_F(StateModelTest, eventContextAccessors) {
359     // Construct the event definitions, normally done by startModel.
360     ASSERT_NO_THROW(defineEvents());
361     ASSERT_NO_THROW(verifyEvents());
362 
363     // Verify the post-construction values.
364     EXPECT_EQ(NOP_EVT, getNextEvent());
365     EXPECT_EQ(NOP_EVT, getLastEvent());
366 
367     // Call setEvent which will update both next event and last event.
368     EXPECT_NO_THROW(postNextEvent(START_EVT));
369 
370     // Verify the values are what we expect.
371     EXPECT_EQ(START_EVT, getNextEvent());
372     EXPECT_EQ(NOP_EVT, getLastEvent());
373 
374     // Call setEvent again.
375     EXPECT_NO_THROW(postNextEvent(WORK_START_EVT));
376 
377     // Verify the values are what we expect.
378     EXPECT_EQ(WORK_START_EVT, getNextEvent());
379     EXPECT_EQ(START_EVT, getLastEvent());
380 
381     // Verify that posting an undefined event throws.
382     EXPECT_THROW(postNextEvent(9999), StateModelError);
383 }
384 
385 /// @brief Tests the fundamental methods used for state handler mapping.
386 /// Verifies the ability to search for and add entries in the state handler map.
TEST_F(StateModelTest,stateDefinition)387 TEST_F(StateModelTest, stateDefinition) {
388     // After construction, the state dictionary should be empty. Verify that
389     // getState will throw when, state is not defined.
390     EXPECT_THROW(getState(READY_ST), StateModelError);
391 
392     // Verify that we can add a state to the dictionary.
393     ASSERT_NO_THROW(defineState(READY_ST, "READY_ST",
394                                 std::bind(&StateModelTest::dummyHandler,
395                                           this)));
396 
397     // Verify that we can find the state by its value.
398     StatePtr state;
399     EXPECT_NO_THROW(state = getState(READY_ST));
400     EXPECT_TRUE(state);
401 
402     // Verify the state's value and label.
403     EXPECT_EQ(READY_ST, state->getValue());
404     EXPECT_EQ("READY_ST", state->getLabel());
405 
406     // Now verify that retrieved state's handler executes the correct method.
407     // Make sure the dummy called flag is false prior to invocation.
408     EXPECT_FALSE(getDummyCalled());
409 
410     // Invoke the state's handler.
411     EXPECT_NO_THROW(state->run());
412 
413     // Verify the dummy called flag is now true.
414     EXPECT_TRUE(getDummyCalled());
415 
416     // Verify that we cannot add a duplicate.
417     EXPECT_THROW(defineState(READY_ST, "READY_ST",
418                              std::bind(&StateModelTest::readyHandler, this)),
419                  StateModelError);
420 
421     // Verify that we can still find the state.
422     EXPECT_NO_THROW(getState(READY_ST));
423 }
424 
425 /// @brief Tests state dictionary initialization and validation.
426 /// This tests the basic concept of state dictionary initialization and
427 /// verification by manually invoking the methods normally called by startModel.
TEST_F(StateModelTest,stateDictionary)428 TEST_F(StateModelTest, stateDictionary) {
429     // Verify that the map validation throws prior to the dictionary being
430     // initialized.
431     EXPECT_THROW(verifyStates(), StateModelError);
432 
433     // Construct the dictionary and verify it.
434     ASSERT_NO_THROW(defineStates());
435     EXPECT_NO_THROW(verifyStates());
436 
437     // Verify the base class states.
438     EXPECT_TRUE(checkState(NEW_ST, "NEW_ST"));
439     EXPECT_TRUE(checkState(END_ST, "END_ST"));
440 
441     // Verify stub class states.
442     EXPECT_TRUE(checkState(DUMMY_ST, "DUMMY_ST"));
443     EXPECT_TRUE(checkState(READY_ST, "READY_ST"));
444     EXPECT_TRUE(checkState(DO_WORK_ST, "DO_WORK_ST"));
445     EXPECT_TRUE(checkState(DONE_ST, "DONE_ST"));
446 
447     // Verify that undefined states are handled correctly.
448     EXPECT_THROW(getState(9999), StateModelError);
449     EXPECT_EQ(LabeledValueSet::UNDEFINED_LABEL, getStateLabel(9999));
450 }
451 
452 /// @brief General testing of state context accessors.
453 /// Most if not all of these are also tested as a byproduct off larger tests.
TEST_F(StateModelTest,stateContextAccessors)454 TEST_F(StateModelTest, stateContextAccessors) {
455     // setState will throw unless we initialize the handler map.
456     ASSERT_NO_THROW(defineStates());
457     ASSERT_NO_THROW(verifyStates());
458 
459     // Verify post-construction state values.
460     EXPECT_EQ(NEW_ST, getCurrState());
461     EXPECT_EQ(NEW_ST, getPrevState());
462 
463     // Call setState which will update both state and previous state.
464     EXPECT_NO_THROW(setState(READY_ST));
465 
466     // Verify the values are what we expect.
467     EXPECT_EQ(READY_ST, getCurrState());
468     EXPECT_EQ(NEW_ST, getPrevState());
469 
470     // Call setState again.
471     EXPECT_NO_THROW(setState(DO_WORK_ST));
472 
473     // Verify the values are what we expect.
474     EXPECT_EQ(DO_WORK_ST, getCurrState());
475     EXPECT_EQ(READY_ST, getPrevState());
476 
477     // Verify that calling setState with an state that has no handler
478     // will throw.
479     EXPECT_THROW(setState(-1), StateModelError);
480 
481     // Verify that calling setState with NEW_ST is ok.
482     EXPECT_NO_THROW(setState(NEW_ST));
483 
484     // Verify that calling setState with END_ST is ok.
485     EXPECT_NO_THROW(setState(END_ST));
486 
487     // Verify that calling setState with an undefined state throws.
488     EXPECT_THROW(setState(9999), StateModelError);
489 }
490 
491 /// @brief Checks that invoking runModel prior to startModel is not allowed.
TEST_F(StateModelTest,runBeforeStart)492 TEST_F(StateModelTest, runBeforeStart) {
493     // Verify that the failure explanation is empty and work is not done.
494     EXPECT_TRUE(getFailureExplanation().empty());
495 
496     // Attempt to call runModel before startModel.  This should result in an
497     // orderly model failure.
498     ASSERT_NO_THROW(runModel(START_EVT));
499 
500     // Check that state and event are correct.
501     EXPECT_EQ(END_ST, getCurrState());
502     EXPECT_EQ(FAIL_EVT, getNextEvent());
503 
504     // Verify that failure explanation is not empty.
505     EXPECT_FALSE(getFailureExplanation().empty());
506 }
507 
508 /// @brief Tests that the endModel may be used to transition the model to
509 /// a normal conclusion.
TEST_F(StateModelTest,transitionWithEnd)510 TEST_F(StateModelTest, transitionWithEnd) {
511     // Init dictionaries manually, normally done by startModel.
512     initDictionaries();
513 
514     // call transition to move from NEW_ST to DUMMY_ST with START_EVT
515     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
516 
517     //  Verify that state and event members are as expected.
518     EXPECT_EQ(DUMMY_ST, getCurrState());
519     EXPECT_EQ(NEW_ST, getPrevState());
520     EXPECT_EQ(START_EVT, getNextEvent());
521     EXPECT_EQ(NOP_EVT, getLastEvent());
522 
523     // Call endModel to transition us to the end of the model.
524     EXPECT_NO_THROW(endModel());
525 
526     // Verify state and event members are correctly set.
527     EXPECT_EQ(END_ST, getCurrState());
528     EXPECT_EQ(DUMMY_ST, getPrevState());
529     EXPECT_EQ(END_EVT, getNextEvent());
530     EXPECT_EQ(START_EVT, getLastEvent());
531 }
532 
533 /// @brief Tests that the abortModel may be used to transition the model to
534 /// failed conclusion.
TEST_F(StateModelTest,transitionWithAbort)535 TEST_F(StateModelTest, transitionWithAbort) {
536     // Init dictionaries manually, normally done by startModel.
537     initDictionaries();
538 
539     // call transition to move from NEW_ST to DUMMY_ST with START_EVT
540     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
541 
542     //  Verify that state and event members are as expected.
543     EXPECT_EQ(DUMMY_ST, getCurrState());
544     EXPECT_EQ(NEW_ST, getPrevState());
545     EXPECT_EQ(START_EVT, getNextEvent());
546     EXPECT_EQ(NOP_EVT, getLastEvent());
547 
548     // Call endModel to transition us to the end of the model.
549     EXPECT_NO_THROW(abortModel("test invocation"));
550 
551     // Verify state and event members are correctly set.
552     EXPECT_EQ(END_ST, getCurrState());
553     EXPECT_EQ(DUMMY_ST, getPrevState());
554     EXPECT_EQ(FAIL_EVT, getNextEvent());
555     EXPECT_EQ(START_EVT, getLastEvent());
556 }
557 
558 /// @brief Tests that the boolean indicators for on state entry and exit
559 /// work properly.
TEST_F(StateModelTest,doFlags)560 TEST_F(StateModelTest, doFlags) {
561     // Init dictionaries manually, normally done by startModel.
562     initDictionaries();
563 
564     // Verify that "do" flags are false.
565     EXPECT_FALSE(doOnEntry());
566     EXPECT_FALSE(doOnExit());
567 
568     // call transition to move from NEW_ST to DUMMY_ST with START_EVT
569     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
570 
571     // We are transitioning states, so "do" flags should be true.
572     EXPECT_TRUE(doOnEntry());
573     EXPECT_TRUE(doOnExit());
574 
575     // "do" flags are one-shots, so they should now both be false.
576     EXPECT_FALSE(doOnEntry());
577     EXPECT_FALSE(doOnExit());
578 
579     // call transition to re-enter same state, "do" flags should be false.
580     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
581 
582     // "do" flags should be false.
583     EXPECT_FALSE(doOnEntry());
584     EXPECT_FALSE(doOnExit());
585 
586 }
587 
588 /// @brief Verifies that the model status methods accurately reflect the model
589 /// status.  It also verifies that the dictionaries can be modified before
590 /// the model is running but not after.
TEST_F(StateModelTest,statusMethods)591 TEST_F(StateModelTest, statusMethods) {
592     // Init dictionaries manually, normally done by startModel.
593     initDictionaries();
594 
595     // After construction, state model is "new", all others should be false.
596     EXPECT_TRUE(isModelNew());
597     EXPECT_FALSE(isModelRunning());
598     EXPECT_FALSE(isModelWaiting());
599     EXPECT_FALSE(isModelDone());
600     EXPECT_FALSE(didModelFail());
601 
602     // Verify that events and states can be added before the model is started.
603     EXPECT_NO_THROW(defineEvent(9998, "9998"));
604     EXPECT_NO_THROW(defineState(9998, "9998",
605                                 std::bind(&StateModelTest::readyHandler,
606                                           this)));
607 
608     // "START" the model.
609     // Fake out starting the model by calling transition to move from NEW_ST
610     // to DUMMY_ST with START_EVT.  If we used startModel this would blow by
611     // the status  of "running" but not "waiting".
612     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
613 
614 
615     // Verify that events and states cannot be added after the model is started.
616     EXPECT_THROW(defineEvent(9999, "9999"), StateModelError);
617     EXPECT_THROW(defineState(9999, "9999",
618                              std::bind(&StateModelTest::readyHandler, this)),
619                  StateModelError);
620 
621     // The state and event combos set above, should show the model as
622     // "running", all others should be false.
623     EXPECT_FALSE(isModelNew());
624     EXPECT_TRUE(isModelRunning());
625     EXPECT_FALSE(isModelWaiting());
626     EXPECT_FALSE(isModelDone());
627     EXPECT_FALSE(didModelFail());
628 
629     // call transition to submit NOP_EVT to current state, DUMMY_ST.
630     EXPECT_NO_THROW(transition(DUMMY_ST, NOP_EVT));
631 
632     // Verify the status methods are correct: with next event set to NOP_EVT,
633     // model should be "running" and "waiting".
634     EXPECT_FALSE(isModelNew());
635     EXPECT_TRUE(isModelRunning());
636     EXPECT_TRUE(isModelWaiting());
637     EXPECT_FALSE(isModelDone());
638     EXPECT_FALSE(didModelFail());
639 
640     // Call endModel to transition us to the end of the model.
641     EXPECT_NO_THROW(endModel());
642 
643     // With state set to END_ST, model should be done.
644     EXPECT_FALSE(isModelNew());
645     EXPECT_FALSE(isModelRunning());
646     EXPECT_FALSE(isModelWaiting());
647     EXPECT_TRUE(isModelDone());
648     EXPECT_FALSE(didModelFail());
649 }
650 
651 /// @brief Tests that the model status methods are correct after a model
652 /// failure.
TEST_F(StateModelTest,statusMethodsOnFailure)653 TEST_F(StateModelTest, statusMethodsOnFailure) {
654     // Construct the event and state definitions, normally done by startModel.
655     ASSERT_NO_THROW(defineEvents());
656     ASSERT_NO_THROW(verifyEvents());
657     ASSERT_NO_THROW(defineStates());
658     ASSERT_NO_THROW(verifyStates());
659 
660     // call transition to move from NEW_ST to DUMMY_ST with START_EVT
661     EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
662 
663     // Call endModel to transition us to the end of the model.
664     EXPECT_NO_THROW(abortModel("test invocation"));
665 
666     // With state set to END_ST, model should be done.
667     EXPECT_FALSE(isModelNew());
668     EXPECT_FALSE(isModelRunning());
669     EXPECT_FALSE(isModelWaiting());
670     EXPECT_TRUE(isModelDone());
671     EXPECT_TRUE(didModelFail());
672 }
673 
674 /// @brief Checks that the context strings accurately reflect context and
675 /// are safe to invoke.
TEST_F(StateModelTest,contextStrs)676 TEST_F(StateModelTest, contextStrs) {
677     // Verify context methods do not throw prior to dictionary init.
678     ASSERT_NO_THROW(getContextStr());
679     ASSERT_NO_THROW(getPrevContextStr());
680 
681     // Construct the event and state definitions, normally done by startModel.
682     ASSERT_NO_THROW(defineEvents());
683     ASSERT_NO_THROW(verifyEvents());
684     ASSERT_NO_THROW(defineStates());
685     ASSERT_NO_THROW(verifyStates());
686 
687     // transition uses setState and setEvent, testing it tests all three.
688     EXPECT_NO_THROW(transition(READY_ST, START_EVT));
689 
690     // Verify the current context string depicts correct state and event.
691     std::string ctx_str;
692     ASSERT_NO_THROW(ctx_str = getContextStr());
693     EXPECT_NE(std::string::npos, ctx_str.find(getStateLabel(READY_ST)));
694     EXPECT_NE(std::string::npos, ctx_str.find(getEventLabel(START_EVT)));
695 
696     // Verify the previous context string depicts correct state and event.
697     ASSERT_NO_THROW(ctx_str = getPrevContextStr());
698     EXPECT_NE(std::string::npos, ctx_str.find(getStateLabel(NEW_ST)));
699     EXPECT_NE(std::string::npos, ctx_str.find(getEventLabel(NOP_EVT)));
700 }
701 
702 /// @brief Tests that undefined states are handled gracefully.
703 /// This test verifies that attempting to transition to an undefined state,
704 /// which constitutes a model violation, results in an orderly model failure.
TEST_F(StateModelTest,undefinedState)705 TEST_F(StateModelTest, undefinedState) {
706     // Verify that the failure explanation is empty and work is not done.
707     EXPECT_TRUE(getFailureExplanation().empty());
708     EXPECT_FALSE(getWorkCompleted());
709 
710     // First, lets execute the state model to a known valid point, by
711     // calling startModel. This should run the model through to DO_WORK_ST.
712     ASSERT_NO_THROW(startModel(READY_ST));
713 
714     // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
715     EXPECT_EQ(DO_WORK_ST, getCurrState());
716     EXPECT_EQ(NOP_EVT, getNextEvent());
717 
718     // Resume the model with next event set to cause the DO_WORK_ST handler
719     // to transition to an undefined state. This should cause it to return
720     // without throwing and yield a failed model.
721     EXPECT_NO_THROW(runModel(FORCE_UNDEFINED_ST_EVT));
722 
723     // Verify that status methods are correct: model is done but failed.
724     EXPECT_FALSE(isModelNew());
725     EXPECT_FALSE(isModelRunning());
726     EXPECT_FALSE(isModelWaiting());
727     EXPECT_TRUE(isModelDone());
728     EXPECT_TRUE(didModelFail());
729 
730     // Verify that failure explanation is not empty.
731     EXPECT_FALSE(getFailureExplanation().empty());
732 
733     // Verify that work completed flag is still false.
734     EXPECT_FALSE(getWorkCompleted());
735 }
736 
737 /// @brief Tests that an unexpected exception thrown by a state handler is
738 /// handled gracefully.  State models are supposed to account for and handle
739 /// all errors that they actions (i.e. handlers) may cause.  In the event they
740 /// do not, this constitutes a model violation.  This test verifies such
741 /// violations are handled correctly and result in an orderly model failure.
TEST_F(StateModelTest,unexpectedError)742 TEST_F(StateModelTest, unexpectedError) {
743     // Verify that the failure explanation is empty and work is not done.
744     EXPECT_TRUE(getFailureExplanation().empty());
745     EXPECT_FALSE(getWorkCompleted());
746 
747     // First, lets execute the state model to a known valid point, by
748     // calling startModel with a start state of READY_ST.
749     // This should run the model through to DO_WORK_ST.
750     ASSERT_NO_THROW(startModel(READY_ST));
751 
752     // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
753     EXPECT_EQ(DO_WORK_ST, getCurrState());
754     EXPECT_EQ(NOP_EVT, getNextEvent());
755 
756     // Resume the model with next event set to cause the DO_WORK_ST handler
757     // to transition to an undefined state. This should cause it to return
758     // without throwing and yield a failed model.
759     EXPECT_NO_THROW(runModel(SIMULATE_ERROR_EVT));
760 
761     // Verify that status methods are correct: model is done but failed.
762     EXPECT_FALSE(isModelNew());
763     EXPECT_FALSE(isModelRunning());
764     EXPECT_FALSE(isModelWaiting());
765     EXPECT_TRUE(isModelDone());
766     EXPECT_TRUE(didModelFail());
767 
768     // Verify that failure explanation is not empty.
769     EXPECT_FALSE(getFailureExplanation().empty());
770 
771     // Verify that work completed flag is still false.
772     EXPECT_FALSE(getWorkCompleted());
773 }
774 
775 /// @brief Tests that undefined events are handled gracefully.
776 /// This test verifies that submitting an undefined event to the state machine
777 /// results, which constitutes a model violation, results in an orderly model
778 /// failure.
TEST_F(StateModelTest,undefinedEvent)779 TEST_F(StateModelTest, undefinedEvent) {
780     // Verify that the failure explanation is empty and work is not done.
781     EXPECT_TRUE(getFailureExplanation().empty());
782     EXPECT_FALSE(getWorkCompleted());
783 
784     // First, lets execute the state model to a known valid point, by
785     // calling startModel with a start state of READY_ST.
786     // This should run the model through to DO_WORK_ST.
787     ASSERT_NO_THROW(startModel(READY_ST));
788 
789     // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
790     EXPECT_EQ(DO_WORK_ST, getCurrState());
791     EXPECT_EQ(NOP_EVT, getNextEvent());
792 
793     // Attempting to post an undefined event within runModel should cause it
794     // to return without throwing and yield a failed model.
795     EXPECT_NO_THROW(runModel(9999));
796 
797     // Verify that status methods are correct: model is done but failed.
798     EXPECT_FALSE(isModelNew());
799     EXPECT_FALSE(isModelRunning());
800     EXPECT_FALSE(isModelWaiting());
801     EXPECT_TRUE(isModelDone());
802     EXPECT_TRUE(didModelFail());
803 
804     // Verify that failure explanation is not empty.
805     EXPECT_FALSE(getFailureExplanation().empty());
806 
807     // Verify that work completed flag is still false.
808     EXPECT_FALSE(getWorkCompleted());
809 }
810 
811 /// @brief Test the basic mechanics of state model execution.
812 /// This test exercises the ability to execute state model from start to
813 /// finish, including the handling of a asynchronous IO operation.
TEST_F(StateModelTest,stateModelTest)814 TEST_F(StateModelTest, stateModelTest) {
815     // Verify that status methods are correct: model is new.
816     EXPECT_TRUE(isModelNew());
817     EXPECT_FALSE(isModelRunning());
818     EXPECT_FALSE(isModelWaiting());
819     EXPECT_FALSE(isModelDone());
820 
821     // Verify that the failure explanation is empty and work is not done.
822     EXPECT_TRUE(getFailureExplanation().empty());
823     EXPECT_FALSE(getWorkCompleted());
824 
825     // Launch the transaction by calling startModel.  The state model
826     // should run up until the simulated async work operation is initiated
827     // in DO_WORK_ST.
828     ASSERT_NO_THROW(startModel(READY_ST));
829 
830     // Verify that we are now in state of DO_WORK_ST, the last event was
831     // WORK_START_EVT, the next event is NOP_EVT.
832     EXPECT_EQ(DO_WORK_ST, getCurrState());
833     EXPECT_EQ(WORK_START_EVT, getLastEvent());
834     EXPECT_EQ(NOP_EVT, getNextEvent());
835 
836     // Simulate completion of async work completion by resuming runModel with
837     // an event of WORK_DONE_EVT.
838     ASSERT_NO_THROW(runModel(WORK_DONE_EVT));
839 
840     // Verify that the state model has progressed through to completion:
841     // it is in the DONE_ST, the status is ST_COMPLETED, and the next event
842     // is NOP_EVT.
843     EXPECT_EQ(END_ST, getCurrState());
844     EXPECT_EQ(END_EVT, getNextEvent());
845 
846     // Verify that status methods are correct: model done.
847     EXPECT_FALSE(isModelNew());
848     EXPECT_FALSE(isModelRunning());
849     EXPECT_FALSE(isModelWaiting());
850     EXPECT_TRUE(isModelDone());
851 
852     // Verify that failure explanation is empty.
853     EXPECT_TRUE(getFailureExplanation().empty());
854 
855     // Verify that work completed flag is true.
856     EXPECT_TRUE(getWorkCompleted());
857 }
858 
859 // This test verifies the pausing and un-pausing capabilities of the state
860 // model.
TEST_F(StateModelTest,stateModelPause)861 TEST_F(StateModelTest, stateModelPause) {
862     // Verify that status methods are correct: model is new.
863     EXPECT_TRUE(isModelNew());
864     EXPECT_FALSE(isModelRunning());
865     EXPECT_FALSE(isModelWaiting());
866     EXPECT_FALSE(isModelDone());
867     EXPECT_FALSE(isModelPaused());
868 
869     // Verify that the failure explanation is empty and work is not done.
870     EXPECT_TRUE(getFailureExplanation().empty());
871     EXPECT_FALSE(getWorkCompleted());
872 
873     // Transition straight to the state in which the model should always
874     // pause.
875     ASSERT_NO_THROW(startModel(PAUSE_ALWAYS_ST));
876 
877     // Verify it was successful and that the model is paused.
878     EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
879     EXPECT_TRUE(isModelPaused());
880 
881     // Run the model again. It should still be paused.
882     ASSERT_NO_THROW(runModel(NOP_EVT));
883     EXPECT_TRUE(isModelPaused());
884 
885     // Unpause the model and transition to the state in which the model
886     // should be paused at most once.
887     unpauseModel();
888     transition(PAUSE_ONCE_ST, NOP_EVT);
889     EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
890     EXPECT_TRUE(isModelPaused());
891 
892     // The model should still be paused until explicitly unpaused.
893     ASSERT_NO_THROW(runModel(NOP_EVT));
894     EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
895     EXPECT_TRUE(isModelPaused());
896 
897     unpauseModel();
898 
899     // Transition back to the first state. The model should pause again.
900     transition(PAUSE_ALWAYS_ST, NOP_EVT);
901     EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
902     EXPECT_TRUE(isModelPaused());
903 
904     ASSERT_NO_THROW(runModel(NOP_EVT));
905     EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
906     EXPECT_TRUE(isModelPaused());
907 
908     // Unpause the model and transition to the state in which the model
909     // should pause only once. This time it should not pause.
910     unpauseModel();
911     transition(PAUSE_ONCE_ST, NOP_EVT);
912     EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
913     EXPECT_FALSE(isModelPaused());
914 }
915 
916 }
917