68 std::cout <<
"=== Abort ordering (abort must not wait on controller_service) ===" << std::endl;
72 int udp = socket(AF_INET, SOCK_DGRAM, 0);
74 setsockopt(
udp, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt));
75 struct sockaddr_in
a{};
76 a.sin_family = AF_INET;
77 a.sin_addr.s_addr = INADDR_ANY;
79 if (bind(
udp,
reinterpret_cast<struct sockaddr*
>(&
a),
sizeof(
a)) < 0) {
80 std::cerr <<
"SKIP: cannot bind UDP " <<
kAbortPort <<
" (" << strerror(errno)
81 <<
") — another process is using the abort port" << std::endl;
86 std::atomic<bool> got_abort{
false};
87 std::atomic<long long> abort_at_ms{-1};
88 std::atomic<bool> listening{
true};
89 const auto t0 = Clock::now();
90 std::thread listener([&]() {
92 struct timeval tv{.tv_sec = 0, .tv_usec = 100000};
93 setsockopt(
udp, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv));
95 ssize_t
n = recv(
udp, buf,
sizeof(buf), 0);
98 std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - t0)
106 const std::string cfg_path =
"test_abort_ordering_cfg.toml";
108 std::ofstream f(cfg_path);
109 f <<
"[database]\nhost=\"127.0.0.1\"\nport=1\n\n"
110 <<
"[server_heartbeat]\nbroadcast_ip=\"" <<
kAbortIp
111 <<
"\"\nbroadcast_port=" <<
kAbortPort <<
"\n\n"
112 <<
"[controller_service]\nhost=\"192.0.2.1\"\nport=8000\n\n"
113 <<
"[fire]\nstate=\"Fire\"\nexpiry_target=\"Armed\"\n"
114 <<
"duration_ms=30000\nextended_ms=60000\n";
118 if (!svc.
init(cfg_path)) {
119 std::cerr <<
"FAILED: init (run from the build dir, with config/ reachable)" << std::endl;
123 std::remove(cfg_path.c_str());
135 const auto abort_issued = Clock::now();
139 for (
int i = 0; i < 20 && !got_abort; ++i)
140 std::this_thread::sleep_for(std::chrono::milliseconds(50));
142 const long long issued_ms =
143 std::chrono::duration_cast<std::chrono::milliseconds>(abort_issued - t0).count();
144 const long long latency = got_abort ? (abort_at_ms.load() - issued_ms) : -1;
146 check(got_abort.load(),
"ABORT broadcast was sent");
148 std::cout <<
" abort latency: " << latency <<
" ms" << std::endl;
152 check(latency >= 0 && latency < 200,
153 "ABORT went out ahead of the controller notification and the actuator batch");
159 std::remove(cfg_path.c_str());
161 std::cout << (
g_failures == 0 ?
"✅ PASS" :
"❌ FAIL") << std::endl;