Skip to content

Commit

Permalink
Add tests and code fixes (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
J040M authored Nov 16, 2024
2 parents 1a349f7 + 995d934 commit 9cc602d
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 42 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
84 changes: 84 additions & 0 deletions src/configuration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::Config;
use log::warn;

pub fn get_configuration(args: Vec<String>) -> 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(),
};

if args.len() > 4 {
let ws_port = args[1].clone();
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::<u32>() {
Ok(br) => br,
Err(_) => {
warn!("Failed to parse baudrate. Using default baudrate 115200");
115200
}
},
serial_port,
ws_port,
};
}

configuration
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_get_configuration_defaults() {
let args: Vec<String> = 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<String> = 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<String> = 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");
}
}
31 changes: 4 additions & 27 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use log::{info, warn};
use log::info;
use std::env;
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]
Expand All @@ -16,34 +18,9 @@ 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<String> = 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::<u32>() {
Ok(br) => br,
Err(_) => {
warn!("Failed to parse baudrate. Using default baudrate 115200");
115200
}
},
serial_port,
ws_port,
};
}
let configuration = get_configuration(args);

let addr = format!("0.0.0.0:{}", configuration.ws_port);
info!("Listening on {}", addr);
Expand Down
71 changes: 68 additions & 3 deletions src/serialcom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -88,3 +86,70 @@ fn write_to_port<T: Write>(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<usize> {
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<usize> {
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);
}
}
8 changes: 8 additions & 0 deletions src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
12 changes: 2 additions & 10 deletions src/wscom.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -190,4 +182,4 @@ async fn handle_connection(

error!("ConnectionClosed for {}", peer);
Err(Error::ConnectionClosed)
}
}

0 comments on commit 9cc602d

Please sign in to comment.