Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / nlfaultinjection / repo / tests / TestFaultInjection.cpp
1 /*
2  *
3  *    Copyright 2016-2017 The nlfaultinjection Authors.
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  *
17  */
18
19 /**
20  *    @file
21  *      This file implements unit tests for FaultInjection.{h,cpp}
22  *
23  */
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <nlunit-test.h>
29 #include <nlfaultinjection.hpp>
30
31 using namespace nl::FaultInjection;
32
33 /**
34  * The list of fault IDs
35  */
36 typedef enum
37 {
38     kTestFaultInjectionID_A,
39     kTestFaultInjectionID_B,
40     kTestFaultInjectionID_NumItems,
41
42 } TestFaultInjectionID;
43
44 static const char *sFaultNames[kTestFaultInjectionID_NumItems] = {
45     "A",
46     "B",
47 };
48
49 static const char *sManagerName = "TestFaultMgr";
50
51 /**
52  * Storage for the FaultInjectionManager
53  */
54 static Record sFaultRecordArray[kTestFaultInjectionID_NumItems];
55
56 static int32_t sFaultAArguments[4];
57
58
59 /**
60  * The manager object
61  */
62 static class Manager sTestFaultInMgr;
63
64 static int sNumTimesRebooted = 0;
65 void RebootCB(void)
66 {
67     sNumTimesRebooted++;
68 }
69
70 static int sNumTimesPrinted = 0;
71 void PostInjectionCB(Manager *aManager, Identifier aId, Record *aFaultRecord)
72 {
73     sNumTimesPrinted++;
74     printf("PostInjectionCB: %s, fault %d - %s, numTimesChecked: %u\n",
75             aManager->GetName(), aId, aManager->GetFaultNames()[aId], aFaultRecord->mNumTimesChecked);
76 }
77
78 static GlobalContext sGlobalContext = {
79     {
80         RebootCB,
81         NULL
82     }
83 };
84
85 /**
86  * Getter for the manager object
87  */
88 static Manager &GetTestFIMgr(void)
89 {
90     if (0 == sTestFaultInMgr.GetNumFaults())
91     {
92         sTestFaultInMgr.Init(kTestFaultInjectionID_NumItems, sFaultRecordArray, sManagerName, sFaultNames);
93         memset(&sFaultAArguments, 0, sizeof(sFaultAArguments));
94         sFaultRecordArray[kTestFaultInjectionID_A].mArguments = sFaultAArguments;
95         sFaultRecordArray[kTestFaultInjectionID_A].mLengthOfArguments =
96             static_cast<uint8_t>(sizeof(sFaultAArguments)/sizeof(sFaultAArguments[0]));
97     }
98     return sTestFaultInMgr;
99 }
100
101 static int sLockCounter = 0;
102 static nlTestSuite *sSuite;
103 void TestLock(void *inLockContext)
104 {
105     int *counter = static_cast<int *>(inLockContext);
106
107     NL_TEST_ASSERT(sSuite, *counter == 0);
108
109     (*counter)++;
110 }
111
112 void TestUnlock(void *inLockContext)
113 {
114     int *counter = static_cast<int *>(inLockContext);
115
116     NL_TEST_ASSERT(sSuite, *counter == 1);
117
118     (*counter)--;
119 }
120
121 #define TEST_FAULT_INJECT( aId, aStatements ) \
122     nlFAULT_INJECT(GetTestFIMgr(), aId, aStatements)
123
124 #define TEST_FAULT_INJECT_WITH_ARGS( aId, aProtectedStatements, aUnprotectedStatements ) \
125     nlFAULT_INJECT_WITH_ARGS(GetTestFIMgr(), aId, aProtectedStatements, aUnprotectedStatements )
126
127 static bool DoA()
128 {
129     bool retval = false;
130
131     // Show that we can compile in a whole block; the simplest form is:
132     // TEST_FAULT_INJECT(kTestFaultInjectionID_A, retval = true);
133
134     TEST_FAULT_INJECT(kTestFaultInjectionID_A,
135                       {
136                           int tmp = 0;
137                           tmp++;
138                           retval = true;
139                           --tmp;
140                       });
141
142     return retval;
143 }
144
145 static int DoAWithArgs()
146 {
147     int retval = 0;
148
149     // Show that we can access the arguments saved in the Record
150
151     TEST_FAULT_INJECT_WITH_ARGS(kTestFaultInjectionID_A,
152                       {
153                           int i;
154                           for (i = 0; i < numFaultArgs; i++)
155                           {
156                               printf("arg %d: %d\n", i, faultArgs[i]);
157                               retval += faultArgs[i];
158                           }
159                       },
160                       {
161                           printf("printing without the lock: counter: %d\n", sLockCounter);
162                           NL_TEST_ASSERT(sSuite, sLockCounter == 0);
163                       });
164
165     return retval;
166 }
167
168 static int DoAExportingArgs()
169 {
170     int retval = 0;
171
172     // Show that we can save arguments in the Record from the fault injection
173     // location as a way to export them to the test harness
174
175     {
176         // Usually this block would be implemented with a macro
177
178         nl::FaultInjection::Manager &mgr = GetTestFIMgr();
179         const nl::FaultInjection::Record *records = mgr.GetFaultRecords();
180
181         // Check for existing arguments to tell if the harness has
182         // installed arguments already, not to override them.
183         if (records[kTestFaultInjectionID_A].mNumArguments == 0)
184         {
185             // Assuming this fault id takes two arguments, lets save 4 values,
186             // as to tell the harness that there are two interesting test cases here
187             // The application developer needs to reserve enough space in
188             // records[kTestFaultInjectionID_A].mArguments
189             int32_t args[] = { 1, 2, 10, 20 };
190             uint16_t numArgs = 4;
191             mgr.StoreArgsAtFault(kTestFaultInjectionID_A, numArgs, args);
192         }
193     }
194
195     TEST_FAULT_INJECT_WITH_ARGS(kTestFaultInjectionID_A,
196                       {
197                           int i;
198                           for (i = 0; i < numFaultArgs; i++)
199                           {
200                               printf("arg %d: %d\n", i, faultArgs[i]);
201                               retval += faultArgs[i];
202                           }
203                       },
204                       {
205                           printf("printing without the lock: counter: %d\n", sLockCounter);
206                           NL_TEST_ASSERT(sSuite, sLockCounter == 0);
207                       });
208     return retval;
209 }
210
211 /**
212  * This test uses three callbacks; they are stored in an array so
213  * the test can iterate over them
214  */
215 enum {
216     kNumCallbacks = 3
217 };
218
219 /**
220  * Array of counters, one per callback
221  */
222 static int sCbFnCalled[kNumCallbacks];
223
224 /**
225  * Array or values to be returned by the callbacks
226  */
227 static bool sCbFnRetval[kNumCallbacks];
228
229 /**
230  * Whether callbacks should remove themself
231  */
232 static bool sCbRemoveItself[kNumCallbacks];
233
234 /**
235  * Boolean to tell callback 0 to enable the second fault
236  */
237 static bool sTriggerFault2;
238
239 static bool cbFn0(Identifier aFaultID, Record *aFaultRecord, void *aContext);
240 static bool cbFn1(Identifier aFaultID, Record *aFaultRecord, void *aContext);
241 static bool cbFn2(Identifier aFaultID, Record *aFaultRecord, void *aContext);
242
243 static Callback sCb[kNumCallbacks] = { { cbFn0, NULL, NULL }, { cbFn1, NULL, NULL }, { cbFn2, NULL, NULL } };
244
245 static bool cbFn0(Identifier aFaultID, Record *aFaultRecord, void *aContext)
246 {
247     (void)aFaultID;
248     (void)aFaultRecord;
249     (void)aContext;
250
251     Manager fMgr = GetTestFIMgr();
252
253     sCbFnCalled[0]++;
254
255     if (sTriggerFault2)
256     {
257         (void)fMgr.FailAtFault(kTestFaultInjectionID_B, 0, 1, Manager::kMutexDoNotTake);
258     }
259
260     if (sCbRemoveItself[0])
261     {
262         (void)fMgr.RemoveCallbackAtFault(aFaultID, &sCb[0], Manager::kMutexDoNotTake);
263
264     }
265
266     return sCbFnRetval[0];
267 }
268
269 static bool cbFn1(Identifier aFaultID, Record *aFaultRecord, void *aContext)
270 {
271     (void)aFaultID;
272     (void)aFaultRecord;
273     (void)aContext;
274
275     sCbFnCalled[1]++;
276     return sCbFnRetval[1];
277 }
278 static bool cbFn2(Identifier aFaultID, Record *aFaultRecord, void *aContext)
279 {
280     (void)aFaultID;
281     (void)aFaultRecord;
282     (void)aContext;
283
284     sCbFnCalled[2]++;
285     return sCbFnRetval[2];
286 }
287
288 static nl::FaultInjection::Callback sHarvestArgsID_ACb;
289 static bool cbToHarvestArgs(Identifier aFaultID, Record *aFaultRecord, void *aContext)
290 {
291     nl::FaultInjection::Manager &mgr = GetTestFIMgr();
292     const char *faultName = mgr.GetFaultNames()[aFaultID];
293     (void)aContext;
294
295     if (aFaultID == kTestFaultInjectionID_A)
296     {
297         uint16_t numArgs = aFaultRecord->mNumArguments;
298         if (numArgs)
299         {
300             int i = 0;
301             while (i < numArgs)
302             {
303                 // The harness can grep for strings like this and find the test cases to run
304                 // in subsequent executions
305                 printf("Found test case: %s_%s_s%u_a%u_a%u;\n", mgr.GetName(), faultName, aFaultRecord->mNumTimesChecked,
306                         aFaultRecord->mArguments[i], aFaultRecord->mArguments[i+1]);
307                 i += 2;
308             }
309
310             // also just copy the array out for the sake of this test
311             int32_t *output = static_cast<int32_t *>(aContext);
312             memcpy(output, aFaultRecord->mArguments, aFaultRecord->mNumArguments * sizeof(aFaultRecord->mArguments[0]));
313         }
314     }
315
316     // This callback never triggers the fault
317     return false;
318 }
319
320
321 /**
322  * Test FailAtFault
323  */
324 void TestFailAtFault(nlTestSuite *inSuite, void *inContext)
325 {
326     int32_t err;
327     Manager &fMgr = GetTestFIMgr();
328     bool shouldFail;
329     nl::FaultInjection::Identifier id;
330     uint32_t i;
331     uint32_t maxTimesToFail = 10;
332     uint32_t maxTimesToSkip = 10;
333     uint32_t timesToFail = 0;
334     uint32_t timesToSkip = 0;
335
336     (void)inContext;
337
338     sSuite = inSuite;
339
340     // fMgr is a singleton, get it twice
341     fMgr = GetTestFIMgr();
342
343     SetGlobalContext(&sGlobalContext);
344
345     for (id = 0; id < kTestFaultInjectionID_NumItems; id++)
346     {
347         shouldFail = fMgr.CheckFault(id);
348         NL_TEST_ASSERT(inSuite, shouldFail == false);
349     }
350
351     // out of boundary
352     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_NumItems);
353     NL_TEST_ASSERT(inSuite, shouldFail == false);
354
355     // Test a few combinations of timesToSkip and timesToFail
356     for (timesToFail = 0; timesToFail <= maxTimesToFail; timesToFail++)
357     {
358         for (timesToSkip = 0; timesToSkip <= maxTimesToSkip; timesToSkip++)
359         {
360             err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
361             NL_TEST_ASSERT(inSuite, err == 0);
362
363             shouldFail = fMgr.CheckFault(kTestFaultInjectionID_B);
364             NL_TEST_ASSERT(inSuite, shouldFail == false);
365
366             for (i = 0; i < timesToSkip; i++)
367             {
368                 shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
369                 NL_TEST_ASSERT(inSuite, shouldFail == false);
370             }
371
372             for (i = 0; i < timesToFail; i++)
373             {
374                 shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
375                 NL_TEST_ASSERT(inSuite, shouldFail);
376             }
377
378             shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
379             NL_TEST_ASSERT(inSuite, shouldFail == false);
380         }
381     }
382 }
383
384 /**
385  * TestRebootAndPrintAtFault
386  */
387 void TestRebootAndPrintAtFault(nlTestSuite *inSuite, void *inContext)
388 {
389     int32_t err;
390     Manager &fMgr = GetTestFIMgr();
391     bool shouldFail;
392     uint32_t timesToFail = 1;
393     uint32_t timesToSkip = 0;
394
395     (void)inContext;
396
397     sSuite = inSuite;
398
399     // fMgr is a singleton, get it twice
400     fMgr = GetTestFIMgr();
401
402     SetGlobalContext(&sGlobalContext);
403
404     // Enable logging, to see that it works
405     sNumTimesPrinted = 0;
406     sGlobalContext.mCbTable.mPostInjectionCb = PostInjectionCB;
407
408     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
409     NL_TEST_ASSERT(inSuite, sNumTimesPrinted == 0);
410
411     sNumTimesRebooted = 0;
412
413     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
414     NL_TEST_ASSERT(inSuite, err == 0);
415
416     err = fMgr.RebootAtFault(kTestFaultInjectionID_NumItems);
417     NL_TEST_ASSERT(inSuite, err == -EINVAL);
418
419     err = fMgr.RebootAtFault(kTestFaultInjectionID_A);
420     NL_TEST_ASSERT(inSuite, err == 0);
421
422     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
423     NL_TEST_ASSERT(inSuite, shouldFail == true);
424     NL_TEST_ASSERT(inSuite, sNumTimesRebooted == 1);
425     NL_TEST_ASSERT(inSuite, sNumTimesPrinted == 1);
426
427     sGlobalContext.mCbTable.mPostInjectionCb = NULL;
428 }
429
430 /**
431  * Test the macro
432  */
433 void TestTheMacro(nlTestSuite *inSuite, void *inContext)
434 {
435     int32_t err;
436     Manager &fMgr = GetTestFIMgr();
437     bool failed;
438     uint32_t timesToSkip = 0;
439     uint32_t timesToFail = 1;
440
441     (void)inContext;
442
443     sSuite = inSuite;
444
445     failed = DoA();
446     NL_TEST_ASSERT(inSuite, failed == false);
447
448     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
449     NL_TEST_ASSERT(inSuite, err == 0);
450
451     failed = DoA();
452     NL_TEST_ASSERT(inSuite, failed);
453 }
454
455 /**
456  * Test callbacks
457  */
458 void TestInsertRemoveCallback(nlTestSuite *inSuite, void *inContext)
459 {
460     int32_t err;
461     Manager fMgr = GetTestFIMgr();
462     bool shouldFail;
463     int i, j;
464
465     (void)inContext;
466
467     sSuite = inSuite;
468
469     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_NumItems, &sCb[0]);
470     NL_TEST_ASSERT(inSuite, err == -EINVAL);
471
472     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, NULL);
473     NL_TEST_ASSERT(inSuite, err == -EINVAL);
474
475     // Try removing a callback that's not installed
476     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sCb[0]);
477     NL_TEST_ASSERT(inSuite, err == 0);
478
479     // Now add it
480     err = fMgr.InsertCallbackAtFault(kTestFaultInjectionID_A, &sCb[0]);
481     NL_TEST_ASSERT(inSuite, err == 0);
482
483     // Add it again, should be a no-op (the callback should be called only once)
484     err = fMgr.InsertCallbackAtFault(kTestFaultInjectionID_A, &sCb[0]);
485     NL_TEST_ASSERT(inSuite, err == 0);
486
487     // Try removing one that's not installed with a non-empty list
488     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sCb[1]);
489     NL_TEST_ASSERT(inSuite, err == 0);
490
491     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
492     NL_TEST_ASSERT(inSuite, shouldFail == false);
493     NL_TEST_ASSERT(inSuite, sCbFnCalled[0] == 1);
494     sCbFnCalled[0] = 0;
495     NL_TEST_ASSERT(inSuite, sCbFnCalled[1] == 0);
496
497     // Say the fault is on from the callback
498     sCbFnRetval[0] = true;
499     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
500     NL_TEST_ASSERT(inSuite, shouldFail);
501     sCbFnRetval[0] = false;
502
503     // Turn on the second fault from the first callback; the first should return false,
504     // and then the second should return true
505     sTriggerFault2 = true;
506     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
507     NL_TEST_ASSERT(inSuite, shouldFail == false);
508     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_B);
509     NL_TEST_ASSERT(inSuite, shouldFail);
510
511     // Remove it
512     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sCb[0]);
513     NL_TEST_ASSERT(inSuite, err == 0);
514
515     sCbFnCalled[0] = 0;
516     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
517     NL_TEST_ASSERT(inSuite, shouldFail == false);
518     NL_TEST_ASSERT(inSuite, sCbFnCalled[0] == 0);
519
520     sTriggerFault2 = false;
521
522     // Given three callback on the same fault, test removal of the first one, of the
523     // one in the middle and of the last one.
524     // Keep in mind though that the last one is not really the last one of the list:
525     // all lists end in the two default callbacks.
526     for (i = 0; i < kNumCallbacks; i++)
527     {
528         // add all three
529         for (j = 0; j < kNumCallbacks; j++)
530         {
531             sCbFnCalled[j] = 0;
532             err = fMgr.InsertCallbackAtFault(kTestFaultInjectionID_A, &sCb[j]);
533             NL_TEST_ASSERT(inSuite, err == 0);
534         }
535
536         // remove one
537         err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sCb[i]);
538         NL_TEST_ASSERT(inSuite, err == 0);
539
540         // trigger
541         shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
542         NL_TEST_ASSERT(inSuite, shouldFail == false);
543
544         for (j = 0; j < kNumCallbacks; j++)
545         {
546             if (j == i)
547             {
548                 NL_TEST_ASSERT(inSuite, sCbFnCalled[j] == 0);
549             }
550             else
551             {
552                 NL_TEST_ASSERT(inSuite, sCbFnCalled[j] == 1);
553             }
554         }
555
556         // remove all of them
557         for (j = 0; j < kNumCallbacks; j++)
558         {
559             err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sCb[j]);
560             NL_TEST_ASSERT(inSuite, err == 0);
561             sCbFnCalled[j] = 0;
562         }
563
564         // check that they're all gone
565         shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
566         NL_TEST_ASSERT(inSuite, shouldFail == false);
567         for (j = 0; j < kNumCallbacks; j++)
568         {
569             NL_TEST_ASSERT(inSuite, sCbFnCalled[j] == 0);
570         }
571     }
572 }
573
574 /**
575  * Test a callback that removes itself
576  */
577 void TestCallbackRemovesItself(nlTestSuite *inSuite, void *inContext)
578 {
579     int32_t err;
580     Manager fMgr = GetTestFIMgr();
581     bool shouldFail;
582
583     (void)inContext;
584
585     sSuite = inSuite;
586
587     err = fMgr.InsertCallbackAtFault(kTestFaultInjectionID_A, &sCb[0]);
588     NL_TEST_ASSERT(inSuite, err == 0);
589
590     sCbRemoveItself[0] = true;
591     sCbFnRetval[0] = true;
592
593     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
594     NL_TEST_ASSERT(inSuite, shouldFail == true);
595
596     // Now it returns false, because the callback is gone
597     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
598     NL_TEST_ASSERT(inSuite, shouldFail == false);
599
600     sCbRemoveItself[0] = false;
601     sCbFnRetval[0] = false;
602 }
603
604 /**
605  * Test random failures
606  */
607 void TestFailRandomly(nlTestSuite *inSuite, void *inContext)
608 {
609     int32_t err;
610     Manager fMgr = GetTestFIMgr();
611     bool shouldFail;
612     uint8_t percentage = 80;
613     int numFailures = 0;
614     int numIterations = 100;
615     int i;
616
617     (void)inContext;
618
619     sSuite = inSuite;
620
621     err = fMgr.FailRandomlyAtFault(kTestFaultInjectionID_A, percentage);
622     NL_TEST_ASSERT(inSuite, err == 0);
623     for (i = 0; i < numIterations; i++)
624     {
625         shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
626         if (shouldFail)
627             numFailures++;
628     }
629
630     printf("numFailures: %d\n", numFailures);
631
632     // At the time of this writing, I'm getting 75-82 failures out of 100
633     NL_TEST_ASSERT(inSuite, numFailures > (numIterations/2));
634
635     percentage = 20;
636     numFailures = 0;
637     err = fMgr.FailRandomlyAtFault(kTestFaultInjectionID_A, percentage);
638     NL_TEST_ASSERT(inSuite, err == 0);
639     for (i = 0; i < numIterations; i++)
640     {
641         shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
642         if (shouldFail)
643             numFailures++;
644     }
645
646     printf("numFailures: %d\n", numFailures);
647
648     // At the time of this writing, I'm getting 18-22 failures out of 100
649     NL_TEST_ASSERT(inSuite, numFailures < (numIterations/2));
650
651     err = fMgr.FailRandomlyAtFault(kTestFaultInjectionID_A, 0);
652     NL_TEST_ASSERT(inSuite, err == 0);
653 }
654
655 /**
656  * Test StoreArgsAtFault
657  */
658 void TestArguments(nlTestSuite *inSuite, void *inContext)
659 {
660     int32_t err;
661     Manager fMgr = GetTestFIMgr();
662     bool shouldFail;
663     uint32_t timesToFail = 1;
664     uint32_t timesToSkip = 0;
665     int32_t args[] = { 42, 24 };
666     uint16_t numArgs = static_cast<uint16_t>(sizeof(args)/sizeof(args[0]));
667     int32_t *outArgs = NULL;
668     uint16_t outNumArgs = 0;
669     int retval;
670
671     (void)inContext;
672
673     sSuite = inSuite;
674
675     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
676     NL_TEST_ASSERT(inSuite, err == 0);
677     err = fMgr.StoreArgsAtFault(kTestFaultInjectionID_A, numArgs, args);
678     NL_TEST_ASSERT(inSuite, err == 0);
679     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A, outNumArgs, outArgs);
680     NL_TEST_ASSERT(inSuite, shouldFail);
681     NL_TEST_ASSERT(inSuite, outNumArgs == numArgs);
682     NL_TEST_ASSERT(inSuite, args[0] == outArgs[0]);
683     NL_TEST_ASSERT(inSuite, args[1] == outArgs[1]);
684
685     // Now test the handling of arguments in the macro
686     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
687     NL_TEST_ASSERT(inSuite, err == 0);
688     retval = DoAWithArgs();
689     NL_TEST_ASSERT(inSuite, retval == (args[0] + args[1]));
690 }
691
692
693 /**
694  * Test ParseFaultInjectionStr
695  */
696 void TestParser(nlTestSuite *inSuite, void *inContext)
697 {
698     Manager &fMgr = GetTestFIMgr();
699     bool shouldFail;
700     bool parserVal;
701     nl::FaultInjection::Identifier id;
702     nl::FaultInjection::GetManagerFn faultMgrTable[] = {
703         GetTestFIMgr,
704     };
705     char buffer[80];
706     const char *singleConfig = "TestFaultMgr_A_s0_f1";
707     const char *doubleConfig = "TestFaultMgr_A_s0_f1:TestFaultMgr_B_p50";
708     const char *singleConfigWithArgs = "TestFaultMgr_A_s0_f1_a12_a-7";
709     int retval = 0;
710     int expectedRetVal = (12 -7);
711
712     (void)inContext;
713
714     sSuite = inSuite;
715
716     for (id = 0; id < kTestFaultInjectionID_NumItems; id++)
717     {
718         shouldFail = fMgr.CheckFault(id);
719         NL_TEST_ASSERT(inSuite, shouldFail == false);
720     }
721
722     strncpy(buffer, singleConfig, sizeof(buffer));
723     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
724                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
725     NL_TEST_ASSERT(inSuite, parserVal == true);
726
727     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
728     NL_TEST_ASSERT(inSuite, shouldFail == true);
729     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_B);
730     NL_TEST_ASSERT(inSuite, shouldFail == false);
731
732     strncpy(buffer, doubleConfig, sizeof(buffer));
733     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
734                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
735     NL_TEST_ASSERT(inSuite, parserVal == true);
736     shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
737     NL_TEST_ASSERT(inSuite, shouldFail == true);
738     NL_TEST_ASSERT(inSuite, sFaultRecordArray[1].mPercentage == 50);
739
740     /* reboot */
741     sNumTimesRebooted = 0;
742     singleConfig = "TestFaultMgr_A_s0_f1_r";
743     strncpy(buffer, singleConfig, sizeof(buffer));
744     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
745                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
746     NL_TEST_ASSERT(inSuite, parserVal == true);
747     NL_TEST_ASSERT(inSuite, sFaultRecordArray[0].mReboot == true);
748
749     /* passing parameters */
750     strncpy(buffer, singleConfigWithArgs, sizeof(buffer));
751     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
752                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
753     NL_TEST_ASSERT(inSuite, parserVal == true);
754     retval = DoAWithArgs();
755     NL_TEST_ASSERT(inSuite, retval == expectedRetVal);
756
757     /* Bad strings*/
758     singleConfig = "TestFaultMgr_C_s0_f1";
759     doubleConfig = "TestFaultMgr_A_g0_f1:TestFaultMgr_B_r50";
760
761     strncpy(buffer, singleConfig, sizeof(buffer));
762     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
763                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
764     NL_TEST_ASSERT(inSuite, parserVal == false);
765
766     strncpy(buffer, doubleConfig, sizeof(buffer));
767     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
768                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
769     NL_TEST_ASSERT(inSuite, parserVal == false);
770
771     /* Bad percentage values */
772     singleConfig = "TestFaultMgr_A_p101";
773     strncpy(buffer, singleConfig, sizeof(buffer));
774     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
775                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
776     NL_TEST_ASSERT(inSuite, parserVal == false);
777
778     singleConfig = "TestFaultMgr_A_p-1";
779     strncpy(buffer, singleConfig, sizeof(buffer));
780     parserVal = nl::FaultInjection::ParseFaultInjectionStr(buffer,
781                 faultMgrTable, sizeof(faultMgrTable)/sizeof(faultMgrTable[0]));
782     NL_TEST_ASSERT(inSuite, parserVal == false);
783 }
784
785 /**
786  * Test Exporting argument values to be used in future test runs
787  */
788 void TestExportArguments(nlTestSuite *inSuite, void *inContext)
789 {
790     int32_t err;
791     Manager fMgr = GetTestFIMgr();
792     bool failed = false;
793     int32_t outputContext[4];
794     (void)inContext;
795
796     sSuite = inSuite;
797
798     // cleanup
799     fMgr.StoreArgsAtFault(kTestFaultInjectionID_A, 0, NULL);
800
801     /*
802      * Install a callback to harvest the arguments during a run without
803      * faults
804      */
805     memset(&sHarvestArgsID_ACb, 0, sizeof(sHarvestArgsID_ACb));
806     sHarvestArgsID_ACb.mCallBackFn = cbToHarvestArgs;
807     sHarvestArgsID_ACb.mContext = outputContext;
808     fMgr.InsertCallbackAtFault(kTestFaultInjectionID_A, &sHarvestArgsID_ACb);
809
810     /*
811      * During a sequence without faults, save useful arguments in the
812      * mArguments array
813      */
814
815     failed = DoAExportingArgs();
816     NL_TEST_ASSERT(inSuite, failed == false);
817
818     /* Check the right values got exported */
819     NL_TEST_ASSERT(inSuite, outputContext[0] == 1);
820     NL_TEST_ASSERT(inSuite, outputContext[1] == 2);
821     NL_TEST_ASSERT(inSuite, outputContext[2] == 10);
822     NL_TEST_ASSERT(inSuite, outputContext[3] == 20);
823
824     /* Now a real application would use the values collected above for two more tests */
825
826     /* cleanup */
827     err = fMgr.RemoveCallbackAtFault(kTestFaultInjectionID_A, &sHarvestArgsID_ACb);
828     NL_TEST_ASSERT(inSuite, err == 0);
829 }
830
831 /**
832  * Test ResetFaultCounters
833  */
834 void TestResetFaultCounters(nlTestSuite *inSuite, void *inContext)
835 {
836     int32_t err;
837     Manager &fMgr = GetTestFIMgr();
838     nl::FaultInjection::Identifier id = kTestFaultInjectionID_A;
839     uint32_t timesToFail = 2;
840     uint32_t timesToSkip = 2;
841     bool shouldFail;
842     uint32_t i;
843
844     (void)inContext;
845
846     sSuite = inSuite;
847
848     (void)fMgr.CheckFault(kTestFaultInjectionID_A);
849     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumTimesChecked != 0);
850
851     fMgr.ResetFaultCounters();
852     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumTimesChecked == 0);
853
854     // Now check that resetting the counters does not break the configuration
855     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
856     NL_TEST_ASSERT(inSuite, err == 0);
857
858     for (i = 0; i < timesToFail + timesToSkip; i++)
859     {
860         fMgr.ResetFaultCounters();
861         NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumTimesChecked == 0);
862
863         shouldFail = fMgr.CheckFault(kTestFaultInjectionID_A);
864         if (i < timesToSkip)
865         {
866             NL_TEST_ASSERT(inSuite, shouldFail == false);
867         }
868         else
869         {
870             NL_TEST_ASSERT(inSuite, shouldFail == true);
871         }
872         NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumTimesChecked != 0);
873     }
874 }
875
876 /**
877  * Test ResetFaultConfigurations
878  */
879 void TestResetFaultConfigurations(nlTestSuite *inSuite, void *inContext)
880 {
881     int32_t err;
882     Manager &fMgr = GetTestFIMgr();
883     nl::FaultInjection::Identifier id = kTestFaultInjectionID_A;
884     uint32_t timesToFail = 7;
885     uint32_t timesToSkip = 8;
886     uint8_t percentage = 80;
887
888     (void)inContext;
889
890     sSuite = inSuite;
891
892     err = fMgr.FailAtFault(kTestFaultInjectionID_A, timesToSkip, timesToFail);
893     NL_TEST_ASSERT(inSuite, err == 0);
894
895     err = fMgr.ResetFaultConfigurations();
896     NL_TEST_ASSERT(inSuite, err == 0);
897     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumCallsToSkip == 0);
898     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mNumCallsToFail == 0);
899
900     err = fMgr.FailRandomlyAtFault(id, percentage);
901     NL_TEST_ASSERT(inSuite, err == 0);
902
903     err = fMgr.ResetFaultConfigurations();
904     NL_TEST_ASSERT(inSuite, err == 0);
905     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mPercentage == 0);
906
907     err = fMgr.InsertCallbackAtFault(id, &sCb[0]);
908     NL_TEST_ASSERT(inSuite, err == 0);
909
910     err = fMgr.ResetFaultConfigurations();
911     NL_TEST_ASSERT(inSuite, err == 0);
912     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mCallbackList != &sCb[0]);
913
914     err = fMgr.RebootAtFault(id);
915     NL_TEST_ASSERT(inSuite, err == 0);
916
917     err = fMgr.ResetFaultConfigurations();
918     NL_TEST_ASSERT(inSuite, err == 0);
919     NL_TEST_ASSERT(inSuite, fMgr.GetFaultRecords()[id].mReboot == false);
920 }
921
922 /**
923  *  Test Suite that lists all the test functions.
924  */
925 static const nlTest sTests[] = {
926     NL_TEST_DEF("Test FailAtFault",                TestFailAtFault),
927     NL_TEST_DEF("Test RebootAndPrintAtFault",      TestRebootAndPrintAtFault),
928     NL_TEST_DEF("Test the macro",                  TestTheMacro),
929     NL_TEST_DEF("Test InsertRemoveCallback",       TestInsertRemoveCallback),
930     NL_TEST_DEF("Test CallbackRemovesItself",      TestCallbackRemovesItself),
931     NL_TEST_DEF("Test Random failures",            TestFailRandomly),
932     NL_TEST_DEF("Test Parser",                     TestParser),
933     NL_TEST_DEF("Test Arguments",                  TestArguments),
934     NL_TEST_DEF("Test Exporting useful arguments", TestExportArguments),
935     NL_TEST_DEF("Test ResetFaultCounters",         TestResetFaultCounters),
936     NL_TEST_DEF("Test ResetFaultConfigurations",   TestResetFaultConfigurations),
937     NL_TEST_SENTINEL()
938 };
939
940 /**
941  *  Set up the test suite.
942  */
943 static int TestSetup(void *inContext)
944 {
945     (void)inContext;
946
947     return (SUCCESS);
948 }
949
950 /**
951  *  Tear down the test suite.
952  */
953 static int TestTeardown(void *inContext)
954 {
955     (void)inContext;
956
957     return (SUCCESS);
958 }
959
960 /**
961  *  Main
962  */
963 int main(int argc, char *argv[])
964 {
965     nl::FaultInjection::Manager &mgr = GetTestFIMgr();
966     (void)argc;
967     (void)argv;
968
969     srand(static_cast<unsigned int>(time(NULL)));
970
971     nlTestSuite theSuite;
972     memset(&theSuite, 0, sizeof(theSuite));
973     theSuite.name = "fault-injection";
974     theSuite.tests = &sTests[0];
975     theSuite.setup = TestSetup;
976     theSuite.tear_down = TestTeardown;
977
978     // Set the critical section callbacks once here, instead of in every test
979     mgr.SetLockCallbacks(TestLock, TestUnlock, &sLockCounter);
980
981     // Generate machine-readable, comma-separated value (CSV) output.
982     nl_test_set_output_style(OUTPUT_CSV);
983
984     // Run test suit against one context
985     nlTestRunner(&theSuite, NULL);
986
987     return nlTestRunnerStats(&theSuite);
988 }