Skip to content

Commit

Permalink
test(agent): update request json conversion
Browse files Browse the repository at this point in the history
Signed-off-by: GridexX <[email protected]>
  • Loading branch information
GridexX committed Apr 9, 2023
1 parent d4a0665 commit 1812963
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 136 deletions.
1 change: 1 addition & 0 deletions agent/lib/src/external_api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod model;
pub mod comms;
pub mod service;
14 changes: 10 additions & 4 deletions agent/lib/src/external_api/model.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct FileModel {
pub filename: String,
pub content: String,
Expand All @@ -12,14 +12,14 @@ pub struct CodeEntry {
pub script: Vec<String>, // All commands to execute at startup
}

#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub enum Type {
Status,
Request,
Response,
}

#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub enum Code {
Run,
Ok,
Expand All @@ -40,6 +40,12 @@ impl StatusMessage {
}
}

impl Default for StatusMessage {
fn default() -> Self {
Self::new()
}
}

#[derive(Deserialize, Serialize, Debug)]
pub struct ResponseStep {
pub command: String,
Expand Down Expand Up @@ -96,7 +102,7 @@ impl ResponseMessage {
}
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct RequestStep {
pub command: String,
pub enable_output: bool,
Expand Down
244 changes: 114 additions & 130 deletions agent/lib/src/external_api/service.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use anyhow::{anyhow, Result};
use log::{error, info};
use log::{error, info, debug, trace};

use super::model::{RequestMessage, ResponseMessage, StatusMessage};
use super::comms::{Message, MESSAGE_SIZE_NB_BYTES};

pub struct ExternalApi {
serial_path: String,
Expand All @@ -25,31 +26,76 @@ impl ExternalApi {
.map_err(|e| anyhow!("Failed to open serial port: {}", e))?;

// Create a buffer to hold the data
let mut data_size: usize = 0;
let mut size_buffer: [u8; MESSAGE_SIZE_NB_BYTES] = [0; MESSAGE_SIZE_NB_BYTES];
let mut got_size = false;

let mut buf = [0; 128];
let mut bytes_read: usize = 0;

// Create the final vector to hold the data
let mut data_received: Vec<u8> = Vec::new();

let mut find_delimiter = false;
//we read the buffer and retrieve the first 8 bytes which are the size of the message
while !got_size {
match serial.read(&mut size_buffer) {
Ok(t) => {
if t == 0 {
break;
}

bytes_read += t;
data_received.extend_from_slice(&size_buffer[..t]);

trace!("Received {} bytes", t);
trace!("Size buffer: {:?}", data_received.clone());

if bytes_read >= MESSAGE_SIZE_NB_BYTES {
got_size = true;

let size_string = String::from_utf8(
data_received.clone()
).map_err(
|e| anyhow!("Failed to get message size as string: {}", e)
)?;

trace!("Size string: {}", size_string);

data_size = size_string.parse::<usize>().map_err(
|e| anyhow!("Failed to parse length of message: {}", e)
)?;

data_received.drain(..MESSAGE_SIZE_NB_BYTES);
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => (),
Err(e) => error!("{:?}", e),
}
}

bytes_read = 0;

while !find_delimiter {
while bytes_read < data_size {
match serial.read(&mut buf) {
Ok(t) => {
if t > 0 {
info!("Buffer received {:?}", &buf[..t]);
find_delimiter =
self.append_data_before_delimiter(&buf, &mut data_received)?;
bytes_read += t;
data_received.extend_from_slice(&buf[..t]);
debug!("Received {} bytes", t);
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => (),
Err(e) => error!("{:?}", e),
}
}

info!("Final received data: {:?}", data_received);
debug!("Final received data: {:?}", data_received);
debug!("Total bytes read {:?}", bytes_read);

let code_entry = self.parse_json_payload(&data_received)?;

info!("Code entry: {:?}", code_entry);

// Flush the serial port
serial
.flush()
Expand All @@ -58,29 +104,6 @@ impl ExternalApi {
Ok(code_entry)
}

pub fn append_data_before_delimiter(
&mut self,
buf: &[u8],
data_received: &mut Vec<u8>,
) -> Result<bool> {
// find char 1c (record separator) in the buffer
if let Some(i) = buf.iter().position(|&r| r == 0x1c) {
// Split the buffer at the position of the record separator
let (data_to_add, _) = buf.split_at(i);

// Add the data to the data vector
data_received.extend_from_slice(data_to_add);

info!("Delimiter found at index: {}", i);

Ok(true)
} else {
// Add the data to the data vector
data_received.extend_from_slice(&buf[..buf.len()]);
Ok(false)
}
}

pub fn parse_json_payload(&mut self, data: &[u8]) -> Result<RequestMessage> {
// Convert the data vector to a codeEntry struct
let request_message: RequestMessage = serde_json::from_slice(data)
Expand All @@ -100,7 +123,8 @@ impl ExternalApi {
}

pub fn send_response_message(&mut self, response_message: ResponseMessage) -> Result<()> {
let code_json = serde_json::to_string(&response_message).unwrap();
let code_json = serde_json::to_string(&response_message)
.map_err(|e| anyhow!("Failed to stringify response message : {}", e))?;

// Write the JSON to the serial port
self.write_to_serial(&code_json)?;
Expand All @@ -119,7 +143,8 @@ impl ExternalApi {
.map_err(|e| anyhow!("Failed to open serial port: {}", e))?;

// Conver the string to a byte array
let buf = data.as_bytes();
let message = Message::new(data.to_string()).to_bytes();
let buf = message.as_slice();

// Write the byte array to the serial port
serial
Expand All @@ -139,41 +164,76 @@ mod tests {

use anyhow::Result;

use crate::external_api::model::{Code, FileModel, RequestStep, Type};

use super::ExternalApi;

#[test]
fn test_parse_json_payload() -> Result<()> {
// let mut internal_api = ExternalApi::new("".to_string(), 0);
let mut internal_api = ExternalApi::new("".to_string(), 0);

// Data vector with the following JSON payload:
// {
// "files": [
// "type": "Request",
// "code": "Run",
// "data": {
// "id": "4bf68974-c315-4c41-aee2-3dc2920e76e9",
// "files": [
// {
// "filename": "src/index.js",
// "content": "console.log('Hello World!');"
// }
// ],
// "steps": [
// {
// "filename": "test.py",
// "content": "print('Hello World')"
// "command": "node src/index.js",
// "enable_output": true
// }
// ],
// "script": [
// "python3 test.py"
// ]
// }
// ]
// }
// }

let data = [
123, 10, 32, 32, 34, 102, 105, 108, 101, 115, 34, 58, 32, 91, 10, 32, 32, 32, 32, 123,
10, 32, 32, 32, 32, 32, 32, 34, 102, 105, 108, 101, 110, 97, 109, 101, 34, 58, 32, 34,
116, 101, 115, 116, 46, 112, 121, 34, 44, 10, 32, 32, 32, 32, 32, 32, 34, 99, 111, 110,
116, 101, 110, 116, 34, 58, 32, 34, 112, 114, 105, 110, 116, 40, 39, 72, 101, 108, 108,
111, 32, 87, 111, 114, 108, 100, 39, 41, 34, 10, 32, 32, 32, 32, 125, 10, 32, 32, 93,
44, 10, 32, 32, 34, 115, 99, 114, 105, 112, 116, 34, 58, 32, 91, 10, 32, 32, 32, 32,
34, 112, 121, 116, 104, 111, 110, 51, 32, 116, 101, 115, 116, 46, 112, 121, 34, 10, 32,
32, 93, 10, 32, 32, 10, 125,
123, 10, 32, 32, 34, 116, 121, 112, 101, 34, 58, 32, 34, 82, 101, 113, 117, 101, 115,
116, 34, 44, 10, 32, 32, 34, 99, 111, 100, 101, 34, 58, 32, 34, 82, 117, 110, 34, 44,
10, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 123, 10, 32, 32, 32, 32, 34, 105, 100,
34, 58, 32, 34, 52, 98, 102, 54, 56, 57, 55, 52, 45, 99, 51, 49, 53, 45, 52, 99, 52,
49, 45, 97, 101, 101, 50, 45, 51, 100, 99, 50, 57, 50, 48, 101, 55, 54, 101, 57, 34,
44, 10, 32, 32, 32, 32, 34, 102, 105, 108, 101, 115, 34, 58, 32, 91, 10, 32, 32, 32,
32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 102, 105, 108, 101, 110, 97,
109, 101, 34, 58, 32, 34, 115, 114, 99, 47, 105, 110, 100, 101, 120, 46, 106, 115, 34,
44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 99, 111, 110, 116, 101, 110, 116, 34, 58,
32, 34, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 40, 39, 72, 101, 108, 108,
111, 32, 87, 111, 114, 108, 100, 33, 39, 41, 59, 34, 10, 32, 32, 32, 32, 32, 32, 125,
10, 32, 32, 32, 32, 93, 44, 10, 32, 32, 32, 32, 34, 115, 116, 101, 112, 115, 34, 58,
32, 91, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 99,
111, 109, 109, 97, 110, 100, 34, 58, 32, 34, 110, 111, 100, 101, 32, 115, 114, 99, 47,
105, 110, 100, 101, 120, 46, 106, 115, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34,
101, 110, 97, 98, 108, 101, 95, 111, 117, 116, 112, 117, 116, 34, 58, 32, 116, 114,
117, 101, 10, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 93, 10, 32, 32, 125, 10,
125,
];

// let code_entry = internal_api.parse_json_payload(&data)?;
// assert_eq!(code_entry.files[0].filename, "test.py");
// assert_eq!(code_entry.files[0].content, "print('Hello World')");
// assert_eq!(code_entry.script[0], "python3 test.py");
assert!(true);
let request_message = internal_api.parse_json_payload(&data)?;

let files = vec![FileModel {
filename: "src/index.js".to_string(),
content: "console.log('Hello World!');".to_string(),
}];

let steps = vec![RequestStep {
command: "node src/index.js".to_string(),
enable_output: true,
}];

assert_eq!(request_message.r#type, Type::Request);
assert_eq!(request_message.code, Code::Run);
assert_eq!(
request_message.data.id,
"4bf68974-c315-4c41-aee2-3dc2920e76e9"
);
assert_eq!(request_message.data.files[0], files[0]);
assert_eq!(request_message.data.steps[0], steps[0]);
Ok(())
}

Expand All @@ -199,80 +259,4 @@ mod tests {

Ok(())
}

#[test]
fn test_data_cut_before_delimiter() -> Result<()> {
let mut internal_api = ExternalApi::new("".to_string(), 0);

let data = [97, 98, 99, 28, 1, 2, 3, 4, 5, 6, 7];
let mut data_received: Vec<u8> = Vec::new();

let find_demiliter =
internal_api.append_data_before_delimiter(&data, &mut data_received)?;

assert!(find_demiliter);
assert_eq!(data_received, [97, 98, 99]);

Ok(())
}

#[test]
fn test_data_transferred_without_delimiter() -> Result<()> {
let mut internal_api = ExternalApi::new("".to_string(), 0);

let data = [97, 98, 99, 1, 2, 3, 4, 5, 6, 7];
let mut data_received: Vec<u8> = Vec::new();

let find_demiliter =
internal_api.append_data_before_delimiter(&data, &mut data_received)?;

assert!(!find_demiliter);
assert_eq!(data_received, [97, 98, 99, 1, 2, 3, 4, 5, 6, 7]);

Ok(())
}

#[test]
fn test_data_transferred_multiple_time() -> Result<()> {
let mut internal_api = ExternalApi::new("".to_string(), 0);

let data = [97, 98, 99];
let data2 = [1, 2, 3, 4, 5, 6, 7];
let mut data_received: Vec<u8> = Vec::new();

let find_demiliter =
internal_api.append_data_before_delimiter(&data, &mut data_received)?;
let find_demiliter2 =
internal_api.append_data_before_delimiter(&data2, &mut data_received)?;

assert!(!find_demiliter);
assert!(!find_demiliter2);
assert_eq!(data_received, [97, 98, 99, 1, 2, 3, 4, 5, 6, 7]);

Ok(())
}

#[test]
fn test_data_transferred_with_delimiter() -> Result<()> {
let mut internal_api = ExternalApi::new("".to_string(), 0);

let data = [97, 98, 99];
let data2 = [1, 2, 3, 4, 5, 6, 7];
let data3 = [8, 9, 10, 28, 11, 12, 13];
let mut data_received: Vec<u8> = Vec::new();

let find_demiliter =
internal_api.append_data_before_delimiter(&data, &mut data_received)?;
let find_demiliter2 =
internal_api.append_data_before_delimiter(&data2, &mut data_received)?;
let find_demiliter3 =
internal_api.append_data_before_delimiter(&data3, &mut data_received)?;

assert!(!find_demiliter);
assert!(!find_demiliter2);
assert!(find_demiliter3);
assert_eq!(data_received, [97, 98, 99, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

Ok(())
}
}
4 changes: 2 additions & 2 deletions agent/lib/src/internal_api/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl InternalApi {
#[cfg(test)]
mod tests {
use super::*;
use crate::external_api::model::{CodeEntry, FileModel, RequestData, RequestStep};
use crate::external_api::model::{FileModel, RequestData, RequestStep};
use std::fs::File;
use std::io::Read;

Expand Down Expand Up @@ -246,7 +246,7 @@ mod tests {
//Check that the file contains the specified content
let mut file = File::open(&path).unwrap();
let mut buffer = [0; 12];
file.read(&mut buffer[..]).unwrap();
file.read_exact(&mut buffer[..]).unwrap();

// Convert buffer to string
let content = String::from_utf8(buffer.to_vec()).unwrap();
Expand Down

0 comments on commit 1812963

Please sign in to comment.