From ffdee09bffadabd0f31d0e5b8dd86a518ccbd091 Mon Sep 17 00:00:00 2001 From: Jo Ao Date: Fri, 15 Nov 2024 23:23:16 +0100 Subject: [PATCH 1/4] Seperate functionality from main(). Modify build gh config. --- .github/workflows/build.yml | 4 ++-- src/configuration.rs | 39 +++++++++++++++++++++++++++++++++++++ src/main.rs | 34 ++++---------------------------- tests/struct_test.rs | 0 4 files changed, 45 insertions(+), 32 deletions(-) create mode 100644 src/configuration.rs create mode 100644 tests/struct_test.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0fe6b87..803389b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,9 +11,9 @@ jobs: steps: - name: Install dependencies - run: sudo apt-get update && sudo apt-get install -y libudev-dev + run: sudo apt-get install -y libudev-dev - uses: actions/checkout@v2 - name: Build step - run: cargo build --verbose + run: cargo build --verbose --release - name: Run tests run: cargo test --verbose \ No newline at end of file diff --git a/src/configuration.rs b/src/configuration.rs new file mode 100644 index 0000000..0f3293b --- /dev/null +++ b/src/configuration.rs @@ -0,0 +1,39 @@ +use log::warn; +use std::env; + +use crate::Config; + +pub fn get_configuration() -> Config { + + // Set defaults in case arguments are not provided + let mut configuration = Config { + test_mode: false, + serial_port: "/dev/ttyUSB0".to_string(), + baud_rate: 115200, + ws_port: "9002".to_string(), + }; + + // Set config from start params + let args: Vec = env::args().collect(); + if args.len() > 4 { + let ws_port = args[1].clone(); // Convert String to &str + let serial_port = args[2].clone(); + let baudrate = args[3].clone(); + let test_arg = args[4].clone(); + + configuration = Config { + test_mode: matches!(test_arg.to_lowercase().as_str(), "true"), + baud_rate: match baudrate.parse::() { + Ok(br) => br, + Err(_) => { + warn!("Failed to parse baudrate. Using default baudrate 115200"); + 115200 + } + }, + serial_port, + ws_port, + }; + } + + return configuration; +} diff --git a/src/main.rs b/src/main.rs index c1a4f8f..aed2080 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ -use log::{info, warn}; -use std::env; +use log::info; use tokio::net::TcpListener; +mod configuration; mod commands; mod serialcom; mod structs; mod wscom; use crate::structs::{Config, MessageType, MessageWS}; +use crate::configuration::get_configuration; use crate::wscom::accept_connection; #[tokio::main] @@ -16,34 +17,7 @@ async fn main() { info!("Starting xcontroller..."); - let mut configuration = Config { - test_mode: false, - serial_port: "/dev/ttyUSB0".to_string(), - baud_rate: 115200, - ws_port: "9002".to_string(), - }; - - // Set config from start params - let args: Vec = env::args().collect(); - if args.len() > 4 { - let ws_port = args[1].clone(); // Convert String to &str - let serial_port = args[2].clone(); - let baudrate = args[3].clone(); - let test_arg = args[4].clone(); - - configuration = Config { - test_mode: matches!(test_arg.to_lowercase().as_str(), "true"), - baud_rate: match baudrate.parse::() { - Ok(br) => br, - Err(_) => { - warn!("Failed to parse baudrate. Using default baudrate 115200"); - 115200 - } - }, - serial_port, - ws_port, - }; - } + let configuration = get_configuration(); let addr = format!("0.0.0.0:{}", configuration.ws_port); info!("Listening on {}", addr); diff --git a/tests/struct_test.rs b/tests/struct_test.rs new file mode 100644 index 0000000..e69de29 From 904b0021657c426b02d9192d6111df6b40db9064 Mon Sep 17 00:00:00 2001 From: Jo Ao Date: Sat, 16 Nov 2024 23:16:52 +0100 Subject: [PATCH 2/4] Add tests and refactor --- src/configuration.rs | 63 +++++++++++++++++++++++++++++++++------ src/serialcom.rs | 71 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 0f3293b..2f23066 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,10 +1,7 @@ -use log::warn; -use std::env; - use crate::Config; +use log::warn; -pub fn get_configuration() -> Config { - +pub fn get_configuration(args: Vec) -> Config { // Set defaults in case arguments are not provided let mut configuration = Config { test_mode: false, @@ -13,10 +10,8 @@ pub fn get_configuration() -> Config { ws_port: "9002".to_string(), }; - // Set config from start params - let args: Vec = env::args().collect(); if args.len() > 4 { - let ws_port = args[1].clone(); // Convert String to &str + let ws_port = args[1].clone(); let serial_port = args[2].clone(); let baudrate = args[3].clone(); let test_arg = args[4].clone(); @@ -35,5 +30,55 @@ pub fn get_configuration() -> Config { }; } - return configuration; + return configuration; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_configuration_defaults() { + let args: Vec = vec![]; + let config = get_configuration(args); + + assert_eq!(config.test_mode, false); + assert_eq!(config.serial_port, "/dev/ttyUSB0"); + assert_eq!(config.baud_rate, 115200); + assert_eq!(config.ws_port, "9002"); + } + + #[test] + fn test_get_configuration_with_args() { + let args: Vec = vec![ + "program_name".to_string(), + "8080".to_string(), + "/dev/ttyS0".to_string(), + "9600".to_string(), + "true".to_string(), + ]; + let config = get_configuration(args); + + assert_eq!(config.test_mode, true); + assert_eq!(config.serial_port, "/dev/ttyS0"); + assert_eq!(config.baud_rate, 9600); + assert_eq!(config.ws_port, "8080"); + } + + #[test] + fn test_get_configuration_invalid_baudrate() { + let args: Vec = vec![ + "program_name".to_string(), + "8080".to_string(), + "/dev/ttyS0".to_string(), + "invalid_baudrate".to_string(), + "false".to_string(), + ]; + let config = get_configuration(args); + + assert_eq!(config.test_mode, false); + assert_eq!(config.serial_port, "/dev/ttyS0"); + assert_eq!(config.baud_rate, 115200); // Default baud rate + assert_eq!(config.ws_port, "8080"); + } } diff --git a/src/serialcom.rs b/src/serialcom.rs index d1ebb1f..e678f2d 100644 --- a/src/serialcom.rs +++ b/src/serialcom.rs @@ -23,10 +23,8 @@ pub fn create_serialcom(cmd: &str, serial_port: String, baud_rate: u32) -> Resul } if let Ok(response) = read_from_port(&mut port) { - // Parse message - //Send this message back to WS for broadcast + // Parse message and send this response back to WS for broadcast info!("{}", response); - Ok(response) } else { //Send this message back to WS for broadcast @@ -88,3 +86,70 @@ fn write_to_port(port: &mut T, command: &[u8]) -> io::Result<()> { Err(e) => Err(e), } } + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + + #[test] + fn test_read_from_port_ok() { + let data = b"ok\n"; + let mut cursor = Cursor::new(data); + let result = read_from_port(&mut cursor).unwrap(); + assert_eq!(result, "ok\n"); + } + + // TODO: For this to work a end of message delimiter is needed + + // #[test] + // fn test_read_from_port_partial_ok() { + // let data = b"data and more data"; + // let mut cursor = Cursor::new(data); + // let result = read_from_port(&mut cursor).unwrap(); + // assert_eq!(result, "data and more data"); + // } + + #[test] + fn test_read_from_port_timeout() { + struct TimeoutReader; + impl Read for TimeoutReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::TimedOut, "timeout")) + } + } + + let mut reader = TimeoutReader; + let result = read_from_port(&mut reader); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::TimedOut); + } + + #[test] + fn test_write_to_port_success() { + let mut buffer = Vec::new(); + let command = b"test command"; + let _result = write_to_port(&mut buffer, command).unwrap(); + assert_eq!(buffer, command); + } + + #[test] + fn test_write_to_port_error() { + struct ErrorWriter; + impl Write for ErrorWriter { + fn write(&mut self, _: &[u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::Other, "write error")) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + let mut writer = ErrorWriter; + let command = b"test command"; + let result = write_to_port(&mut writer, command); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::Other); + } +} From 01dbd45eb74d4a96fc66c1803fce6d07637feaa5 Mon Sep 17 00:00:00 2001 From: Jo Ao Date: Sat, 16 Nov 2024 23:17:52 +0100 Subject: [PATCH 3/4] Fix some errors and refactor code --- src/main.rs | 5 ++++- src/structs.rs | 8 ++++++++ src/wscom.rs | 12 ++---------- tests/struct_test.rs | 0 4 files changed, 14 insertions(+), 11 deletions(-) delete mode 100644 tests/struct_test.rs diff --git a/src/main.rs b/src/main.rs index aed2080..1cd62ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use log::info; +use std::env; use tokio::net::TcpListener; mod configuration; @@ -17,7 +18,9 @@ async fn main() { info!("Starting xcontroller..."); - let configuration = get_configuration(); + // Set config from start params + let args: Vec = env::args().collect(); + let configuration = get_configuration(args); let addr = format!("0.0.0.0:{}", configuration.ws_port); info!("Listening on {}", addr); diff --git a/src/structs.rs b/src/structs.rs index 06cfb9d..84371f7 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -77,3 +77,11 @@ pub struct Config { pub baud_rate: u32, pub ws_port: String, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct MessageSender<'a> { + pub message_type: &'a str, + pub message: &'a str, + pub raw_message: String, + pub timestamp: u64, +} \ No newline at end of file diff --git a/src/wscom.rs b/src/wscom.rs index 253761b..e3c40c9 100644 --- a/src/wscom.rs +++ b/src/wscom.rs @@ -1,6 +1,5 @@ use futures::{stream::StreamExt, SinkExt}; use log::{debug, error, info}; -use serde::{Deserialize, Serialize}; use std::net::SocketAddr; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::net::TcpStream; @@ -16,14 +15,7 @@ use crate::serialcom::create_serialcom; use crate::Config; use crate::MessageType; use crate::MessageWS; - -#[derive(Debug, Serialize, Deserialize)] -pub struct MessageSender<'a> { - pub message_type: &'a str, - pub message: &'a str, - pub raw_message: String, - pub timestamp: u64, -} +use crate::structs::MessageSender; // Accept incoming connection from client pub async fn accept_connection(peer: SocketAddr, stream: TcpStream, configuration: Config) { @@ -190,4 +182,4 @@ async fn handle_connection( error!("ConnectionClosed for {}", peer); Err(Error::ConnectionClosed) -} +} \ No newline at end of file diff --git a/tests/struct_test.rs b/tests/struct_test.rs deleted file mode 100644 index e69de29..0000000 From 995d93481e506bfc02f9c72c5927ff6f09c24d7e Mon Sep 17 00:00:00 2001 From: Jo Ao Date: Sat, 16 Nov 2024 23:28:17 +0100 Subject: [PATCH 4/4] Fix return --- src/configuration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configuration.rs b/src/configuration.rs index 2f23066..b11b3d4 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -30,7 +30,7 @@ pub fn get_configuration(args: Vec) -> Config { }; } - return configuration; + configuration } #[cfg(test)]