testsuite: support reboot to retry intermittent tests

When a test fails intermittently there is currently no alternative to
looking at logs and pressing a hardware reset button.  This commit
adds a Kconfig option that can be set when diagnosing an intermittent
failure.  The behavior is to do a cold reset of the board when the
test passes.  A counter is maintained in noinit memory to track the
number of times it takes to reproduce a failure.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
diff --git a/subsys/testsuite/ztest/Kconfig b/subsys/testsuite/ztest/Kconfig
index 52e0efa3..8e4aa73 100644
--- a/subsys/testsuite/ztest/Kconfig
+++ b/subsys/testsuite/ztest/Kconfig
@@ -49,6 +49,14 @@
 	  The override header may now #define the various macros and strings in tc_util.h which are
 	  surrounded by #ifndef ... #endif blocks.
 
+config ZTEST_RETEST_IF_PASSED
+	bool "Reset the board to test again if the test passed"
+	select REBOOT
+	help
+	  If the test passed reset the board so it is run again.  This
+	  may be used as an alternative to manual resets when
+	  attempting to reproduce an intermittent failure.
+
 endif # ZTEST
 
 config ZTEST_MOCKING
diff --git a/subsys/testsuite/ztest/src/ztest.c b/subsys/testsuite/ztest/src/ztest.c
index 4825d91..f6ec059 100644
--- a/subsys/testsuite/ztest/src/ztest.c
+++ b/subsys/testsuite/ztest/src/ztest.c
@@ -10,6 +10,7 @@
 #ifdef CONFIG_USERSPACE
 #include <sys/libc-hooks.h>
 #endif
+#include <power/reboot.h>
 
 #ifdef KERNEL
 static struct k_thread ztest_thread;
@@ -323,5 +324,27 @@
 	z_init_mock();
 	test_main();
 	end_report();
+	if (IS_ENABLED(CONFIG_ZTEST_RETEST_IF_PASSED)) {
+		static __noinit struct {
+			u32_t magic;
+			u32_t boots;
+		} state;
+		const u32_t magic = 0x152ac523;
+
+		if (state.magic != magic) {
+			state.magic = magic;
+			state.boots = 0;
+		}
+		state.boots += 1;
+		if (test_status == 0) {
+			PRINT("Reset board #%u to test again\n",
+				state.boots);
+			k_sleep(K_MSEC(10));
+			sys_reboot(SYS_REBOOT_COLD);
+		} else {
+			PRINT("Failed after %u attempts\n", state.boots);
+			state.boots = 0;
+		}
+	}
 }
 #endif