STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_sequencer_elodin.cpp
Go to the documentation of this file.
1#include <netinet/in.h>
2#include <sys/socket.h>
3#include <unistd.h>
4
5#include <fstream>
6#include <iostream>
7#include <thread>
8#include <vector>
9
11
12using namespace sequencer;
13
14// Dummy TCP server thread to act as Elodin DB
15void dummy_tcp_server(int& out_port, std::vector<uint8_t>& out_data, bool& run) {
16 int server_fd = socket(AF_INET, SOCK_STREAM, 0);
17 int opt = 1;
18 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
19
20 struct sockaddr_in address;
21 address.sin_family = AF_INET;
22 address.sin_addr.s_addr = INADDR_ANY;
23 address.sin_port = 0; // OS assigns random port
24
25 bind(server_fd, (struct sockaddr*)&address, sizeof(address));
26 socklen_t addrlen = sizeof(address);
27 getsockname(server_fd, (struct sockaddr*)&address, &addrlen);
28 out_port = ntohs(address.sin_port);
29
30 listen(server_fd, 1);
31
32 // Non-blocking accept so we can exit if sequenced fails
33 struct timeval tv;
34 tv.tv_sec = 2; // 2 sec timeout
35 tv.tv_usec = 0;
36 setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
37
38 int new_socket = accept(server_fd, nullptr, nullptr);
39 if (new_socket >= 0) {
40 // Connected! Read until closed
41 setsockopt(new_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
42 uint8_t buffer[1024];
43 while (run) {
44 int valread = read(new_socket, buffer, 1024);
45 if (valread <= 0)
46 break;
47 for (int i = 0; i < valread; ++i)
48 out_data.push_back(buffer[i]);
49 }
50 close(new_socket);
51 }
52
53 close(server_fd);
54}
55
56int main() {
57 std::cout << "=== SequencerService Elodin DB Integration Test ===" << std::endl;
58
59 int elodin_port = 0;
60 std::vector<uint8_t> received_data;
61 bool run_server = true;
62
63 std::thread server_thread(dummy_tcp_server, std::ref(elodin_port), std::ref(received_data),
64 std::ref(run_server));
65
66 // Wait for OS to assign port
67 while (elodin_port == 0)
68 std::this_thread::sleep_for(std::chrono::milliseconds(10));
69
70 std::string test_config = "test_elodin_cfg.toml";
71 {
72 std::ofstream f(test_config);
73 f << "[database]\nhost=\"127.0.0.1\"\nport=" << elodin_port << "\n";
74 }
75
77 if (!seq.init(test_config)) {
78 std::cerr << "❌ FAILED: Sequencer init failed (ensure you are running from repository "
79 "root where config/ and external/ exist)\n";
80 run_server = false;
81 server_thread.join();
82 return 1;
83 }
84
85 // Give connection time to establish and schemas to register
86 std::this_thread::sleep_for(std::chrono::milliseconds(100));
87
88 // Trigger State Transition
89 std::cout << "Transitioning to ARMED...\n";
90 seq.transitionTo("Armed");
91
92 std::this_thread::sleep_for(std::chrono::milliseconds(200));
93 run_server = false; // signals server to exit
94 server_thread.join();
95
96 remove(test_config.c_str());
97
98 if (received_data.empty()) {
99 std::cerr << "❌ FAILED: Elodin mock server received 0 bytes\n";
100 return 1;
101 }
102
103 // The VTable schema setup for SequencerState and StateTransition is roughly ~500 bytes and the
104 // 2 actual publishes are another ~35 bytes.
105 if (received_data.size() < 100) {
106 std::cerr << "❌ FAILED: Received unexpectedly small amount of bytes ("
107 << received_data.size() << ") for schemas and data\n";
108 return 1;
109 }
110
111 std::cout << "✅ SUCCESS: Elodin mock server gracefully received " << received_data.size()
112 << " bytes of serialized schemas and state transitions.\n";
113 return 0;
114}
Top-level sequencer service.
bool init(const std::string &config_path="config/config.toml")
Load config, CSVs, connect to Elodin.
bool transitionTo(const std::string &state_name)
Request a state transition by name (e.g.
Definition run.py:1
static double read(int32_t code)
void dummy_tcp_server(int &out_port, std::vector< uint8_t > &out_data, bool &run)