1#[macro_use]
4extern crate log;
5
6use moto_hses_proto as proto;
7use std::collections::HashMap;
8use std::net::SocketAddr;
9
10pub mod handlers;
11pub mod server;
12pub mod state;
13
14pub use handlers::CommandHandler;
15pub use server::MockServer;
16pub use state::{MockState, TypedVariables, VariableType};
17
18#[derive(Debug, Clone)]
20pub struct MockConfig {
21 pub host: String,
22 pub robot_port: u16,
23 pub file_port: u16,
24 pub text_encoding: proto::TextEncoding,
25 pub default_status: proto::Status,
26 pub default_position: proto::Position,
27 pub registers: HashMap<u16, i16>,
28 pub variables: TypedVariables,
29 pub io_states: HashMap<u16, u8>,
30 pub alarms: Vec<proto::Alarm>,
31 pub alarm_history: Vec<proto::Alarm>,
32 pub executing_job: Option<proto::ExecutingJobInfo>,
33 pub cycle_mode: proto::CycleMode,
34}
35
36impl MockConfig {
37 pub fn new(host: impl Into<String>, robot_port: u16, file_port: u16) -> Self {
39 let mut registers = HashMap::new();
40 registers.insert(0, 0);
41 registers.insert(1, 100);
42 registers.insert(2, 200);
43 registers.insert(3, 300);
44 registers.insert(4, 400);
45
46 let mut variables = TypedVariables::new();
47 variables.insert((VariableType::Double, 0), vec![0x01, 0x00, 0x00, 0x00]); variables.insert((VariableType::Double, 1), vec![0x64, 0x00, 0x00, 0x00]); variables.insert((VariableType::Double, 2), vec![0x00, 0x00, 0x20, 0x41]); let mut io_states = HashMap::new();
52 io_states.insert(1, 1); io_states.insert(1001, 0); Self {
56 host: host.into(),
57 robot_port,
58 file_port,
59 text_encoding: proto::TextEncoding::Utf8,
60 default_status: proto::Status::new(
61 proto::StatusData1 {
62 step: false,
63 one_cycle: false,
64 continuous: true,
65 running: false,
66 speed_limited: false,
67 teach: false,
68 play: true,
69 remote: false,
70 },
71 proto::StatusData2 {
72 teach_pendant_hold: false,
73 external_hold: false,
74 command_hold: false,
75 alarm: false,
76 error: false,
77 servo_on: true,
78 },
79 ),
80 default_position: proto::Position::Pulse(proto::PulsePosition::new(vec![
81 0, 0, 0, 0, 0, 0, 0, 0,
82 ])),
83 registers,
84 variables,
85 io_states,
86 alarms: Vec::new(),
87 alarm_history: Vec::new(),
88 executing_job: Some(proto::ExecutingJobInfo::new("TEST.JOB".to_string(), 2, 1, 100)),
89 cycle_mode: proto::CycleMode::Continuous,
90 }
91 }
92
93 pub fn robot_addr(&self) -> Result<SocketAddr, std::net::AddrParseError> {
99 format!("{host}:{port}", host = self.host, port = self.robot_port).parse()
100 }
101
102 pub fn file_addr(&self) -> Result<SocketAddr, std::net::AddrParseError> {
108 format!("{host}:{port}", host = self.host, port = self.file_port).parse()
109 }
110
111 #[must_use]
113 pub fn robot_addr_string(&self) -> String {
114 format!("{host}:{port}", host = self.host, port = self.robot_port)
115 }
116
117 #[must_use]
119 pub fn file_addr_string(&self) -> String {
120 format!("{host}:{port}", host = self.host, port = self.file_port)
121 }
122}
123
124impl Default for MockConfig {
125 fn default() -> Self {
126 Self::new(
127 "127.0.0.1",
128 moto_hses_proto::ROBOT_CONTROL_PORT,
129 moto_hses_proto::FILE_CONTROL_PORT,
130 )
131 }
132}
133
134pub mod test_utils {
136 use super::{MockConfig, MockServer, SocketAddr};
137 use tokio::time::{Duration, sleep};
138
139 pub async fn start_test_server()
144 -> Result<(SocketAddr, tokio::task::JoinHandle<()>), Box<dyn std::error::Error + Send + Sync>>
145 {
146 let mut port = 49152; let mut server = None;
149
150 while port < 65535 && server.is_none() {
151 let test_config = MockConfig::new("127.0.0.1", port, port + 1);
152
153 match MockServer::new(test_config).await {
154 Ok(s) => server = Some(s),
155 Err(_) => port += 2, }
157 }
158
159 let server = server.ok_or("Could not find available port")?;
160 let addr = server.local_addr()?;
161
162 let handle = tokio::spawn(async move {
163 if let Err(e) = server.run().await {
164 error!("Mock server error: {e}");
165 }
166 });
167
168 sleep(Duration::from_millis(200)).await;
170
171 Ok((addr, handle))
172 }
173
174 pub fn create_test_client(
179 addr: SocketAddr,
180 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
181 info!("Test client would connect to {addr}");
184 Ok(())
185 }
186}