1#include "nightmare/internal.h"
2#include <sch/sched.h>
3#include <test/test.h>
4#include <thread/thread.h>
5
6#if defined(TEST_ENABLED) && defined(TEST_NIGHTMARE_SMOKE)
7TEST_GROUP_DEFINE(nightmare);
8
9TEST_DEFINE_UNIT(nightmare, perturb_verdict_mailbox) {
10 char reason[] = "first_reason";
11 char msg[] = "first message";
12 struct nightmare_verdict first = NIGHTMARE_FAIL(reason, msg);
13
14 atomic_store_rlx(&nightmare_runtime.perturb_verdict_ready, false);
15 TEST_ASSERT(!nightmare_load_perturb_verdict(&first));
16
17 nightmare_publish_perturb_verdict(NIGHTMARE_FAIL(reason, msg));
18 reason[0] = 'X';
19 msg[0] = 'X';
20 nightmare_publish_perturb_verdict(
21 NIGHTMARE_FAIL("second_reason", "second message"));
22
23 struct nightmare_verdict loaded;
24 TEST_ASSERT(nightmare_load_perturb_verdict(&loaded));
25 TEST_ASSERT_EQ(loaded.result, NIGHTMARE_RESULT_FAIL);
26 TEST_ASSERT_STR_EQ(loaded.reason, "first_reason");
27 TEST_ASSERT_STR_EQ(loaded.msg, "first message");
28
29 atomic_store_rlx(&nightmare_runtime.perturb_verdict_ready, false);
30 return TEST_SUCCESS;
31}
32
33TEST_DEFINE_UNIT(nightmare, stop_priority) {
34 atomic_store_rlx(&nightmare_runtime.conc.stop, TEST_RUN);
35
36 nightmare_publish_stop(reason: TEST_STOP_BUDGET);
37 TEST_ASSERT_EQ(atomic_load(&nightmare_runtime.conc.stop), TEST_STOP_BUDGET);
38
39 nightmare_stop_after_finding();
40 TEST_ASSERT_EQ(atomic_load(&nightmare_runtime.conc.stop),
41 TEST_STOP_FINDING);
42
43 nightmare_publish_stop(reason: TEST_STOP_BUDGET);
44 TEST_ASSERT_EQ(atomic_load(&nightmare_runtime.conc.stop),
45 TEST_STOP_FINDING);
46
47 nightmare_publish_stop(reason: TEST_STOP_FAIL);
48 TEST_ASSERT_EQ(atomic_load(&nightmare_runtime.conc.stop), TEST_STOP_FAIL);
49
50 nightmare_publish_stop(reason: TEST_STOP_STALL);
51 TEST_ASSERT_EQ(atomic_load(&nightmare_runtime.conc.stop), TEST_STOP_STALL);
52
53 atomic_store_rlx(&nightmare_runtime.conc.stop, TEST_RUN);
54 return TEST_SUCCESS;
55}
56
57static atomic_size_t stop_sleepers_waiting;
58
59static void heartbeat_waiter(void *arg) {
60 cc_ignore(arg);
61 atomic_inc_release(&stop_sleepers_waiting);
62 thread_park();
63}
64
65TEST_DEFINE_UNIT(nightmare, first_stop_wakes_sleepers) {
66 atomic_store_rlx(&stop_sleepers_waiting, 0);
67 atomic_store_rlx(&nightmare_runtime.conc.stop, TEST_RUN);
68
69 struct thread *worker_thread = thread_spawn(
70 "nightmare_stop_worker", heartbeat_waiter, .joinable = true);
71 struct thread *heartbeat = thread_spawn("nightmare_stop_heartbeat",
72 heartbeat_waiter, .joinable = true);
73 TEST_ASSERT_NONNULL(worker_thread);
74 TEST_ASSERT_NONNULL(heartbeat);
75
76 struct test_conc_worker worker = {0};
77 atomic_store_rlx(&worker.th, worker_thread);
78 nightmare_runtime.conc.workers = &worker;
79 nightmare_runtime.conc.worker_count = 1;
80 atomic_store_rlx(&nightmare_runtime.conc.aux, heartbeat);
81 while (atomic_load_acq(&stop_sleepers_waiting) < 2)
82 scheduler_yield();
83
84 nightmare_publish_stop(reason: TEST_STOP_BUDGET);
85 nightmare_runtime.conc.workers = NULL;
86 nightmare_runtime.conc.worker_count = 0;
87 atomic_store_rlx(&nightmare_runtime.conc.aux, NULL);
88
89 bool worker_joined = thread_join_timeout(t: worker_thread, timeout_ms: 250, NULL);
90 if (!worker_joined) {
91 thread_alert(thread: worker_thread);
92 thread_join(t: worker_thread);
93 }
94 bool heartbeat_joined = thread_join_timeout(t: heartbeat, timeout_ms: 250, NULL);
95 if (!heartbeat_joined) {
96 thread_alert(thread: heartbeat);
97 thread_join(t: heartbeat);
98 }
99
100 atomic_store_rlx(&nightmare_runtime.conc.stop, TEST_RUN);
101 TEST_ASSERT(worker_joined);
102 TEST_ASSERT(heartbeat_joined);
103 return TEST_SUCCESS;
104}
105
106TEST_DEFINE_UNIT(nightmare, finding_stop_preserves_finding_verdict) {
107 struct nightmare_verdict verdict =
108 nightmare_verdict_for_stop(NIGHTMARE_OK, stop: TEST_STOP_FINDING);
109 TEST_ASSERT_EQ(verdict.result, NIGHTMARE_RESULT_OK);
110 TEST_ASSERT_EQ(nightmare_result_with_findings(verdict.result, 1),
111 NIGHTMARE_RESULT_FINDING);
112 TEST_ASSERT_EQ(nightmare_result_with_findings(verdict.result, 0),
113 NIGHTMARE_RESULT_OK);
114 return TEST_SUCCESS;
115}
116
117TEST_DEFINE_UNIT(nightmare, forced_stop_verdicts_override_ok) {
118 struct nightmare_verdict failed =
119 nightmare_verdict_for_stop(NIGHTMARE_OK, stop: TEST_STOP_FAIL);
120 TEST_ASSERT_EQ(failed.result, NIGHTMARE_RESULT_FAIL);
121 TEST_ASSERT_STR_EQ(failed.reason, "harness");
122
123 struct nightmare_verdict stalled =
124 nightmare_verdict_for_stop(NIGHTMARE_OK, stop: TEST_STOP_STALL);
125 TEST_ASSERT_EQ(stalled.result, NIGHTMARE_RESULT_STALL);
126 TEST_ASSERT_STR_EQ(stalled.reason, "liveness");
127 return TEST_SUCCESS;
128}
129#endif
130