Skip to content

Commit

Permalink
test(external_api): parse json and check delimiter
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 7f3dd00 commit a809be2
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 54 deletions.
9 changes: 8 additions & 1 deletion agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
agent_lib = { path = "./lib" }
log = "0.4.0"
env_logger = "0.10.0"
anyhow = "1.0.69"
serialport = "4.2.0"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
unshare = "0.7.0"

[lib]
name = "agent_lib"
path = "lib/src/lib.rs"
210 changes: 179 additions & 31 deletions agent/lib/src/external_api/service.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


use anyhow::{anyhow, Result};
use log::{error, info};

Expand All @@ -9,17 +7,14 @@ pub struct ExternalApi {
serial_read_path: String,
serial_write_path: String,
serial_baud_rate: u32,
data_received: Vec<u8>,
}

impl ExternalApi {
pub fn new(serial_read_path: String, serial_write_path: String, serial_baud_rate: u32) -> Self {
let data_received: Vec<u8> = Vec::new();
Self {
serial_read_path,
serial_write_path,
serial_baud_rate,
data_received,
}
}

Expand All @@ -33,37 +28,29 @@ impl ExternalApi {

// Create a buffer to hold the data
let mut buf = [0; 128];
loop {

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

let mut find_delimiter = false;

while !find_delimiter {
match serial.read(&mut buf) {
Ok(t) => {
if t > 0 {
info!("Buffer received {:?}", &buf[..t]);

// 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
self.data_received.extend_from_slice(data_to_add);

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

break;
} else {
// Add the data to the data vector
self.data_received.extend_from_slice(&buf[..t]);
}
find_delimiter =
self.append_data_before_delimiter(&buf, &mut data_received)?;
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => (),
Err(e) => error!("{:?}", e),
}
}

info!("Final received data: {:?}", self.data_received);
let code_entry = self.parse_json_payload()?;
info!("Final received data: {:?}", data_received);

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

// Flush the serial port
serial
Expand All @@ -73,17 +60,36 @@ impl ExternalApi {
Ok(code_entry)
}

pub fn parse_json_payload(&mut self) -> Result<CodeEntry> {

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<CodeEntry> {
// Convert the data vector to a codeEntry struct
let code_entry: CodeEntry = serde_json::from_slice(&self.data_received)
let code_entry: CodeEntry = serde_json::from_slice(data)
.map_err(|e| anyhow!("Failed to parse JSON payload: {}", e))?;

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

// Clear the data vector
self.data_received = Vec::new();

Ok(code_entry)
}

Expand All @@ -108,3 +114,145 @@ impl ExternalApi {
Ok(())
}
}

#[cfg(test)]
mod tests {

use anyhow::Result;

use super::ExternalApi;

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

// Data vector with the following JSON payload:
// {
// "files": [
// {
// "filename": "test.py",
// "content": "print('Hello World')"
// }
// ],
// "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,
];

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");
Ok(())
}

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

// Data vector with missing comma
let data = [
123, 10, 32, 32, 34, 102, 105, 108, 101, 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, 10,
];

let code_entry = internal_api.parse_json_payload(&data);

assert!(code_entry.is_err());

Ok(())
}

#[test]
fn test_data_cut_before_delimiter() -> Result<()> {
let mut internal_api = ExternalApi::new("".to_string(), "".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(), "".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(), "".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(), "".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(())
}
}
1 change: 0 additions & 1 deletion agent/lib/src/internal_api/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ pub struct FileModel {
pub path: PathBuf,
pub file_name: String,
pub content: String,

}

impl FileModel {
Expand Down
36 changes: 16 additions & 20 deletions agent/lib/src/internal_api/service.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::{io::{BufReader, Read}, fs::File, path::{PathBuf, Path}};
use super::model::{CodeReturn, InternalError};
use crate::{external_api::model::CodeEntry, internal_api::model::FileModel};
use anyhow::{anyhow, Result};
use log::{error, info};
use crate::{external_api::model::{CodeEntry}, internal_api::model::FileModel};
use std::io::Write;
use super::model::{CodeReturn, InternalError};
use std::{
fs::File,
io::{BufReader, Read},
path::{Path, PathBuf},
};
use unshare::Command;

const WORKSPACE_PATH: &str = "/tmp";
Expand All @@ -18,15 +22,12 @@ impl InternalApi {
}

pub fn create_workspace(&mut self) -> Result<()> {

info!("Creating workspace for code execution");


// Create a vector of FileModel and a root path
let mut file_models: Vec<FileModel> = Vec::new();
let root_path = PathBuf::from(WORKSPACE_PATH);


self.code_entry.files.iter().for_each(|file| {
let mut file_path = PathBuf::from(&file.filename);
file_path.pop();
Expand All @@ -39,19 +40,19 @@ impl InternalApi {

// Extract the file name from the path and create a FileModel
if let Some(file_name_str) = file_name {

let fns = file_name_str.to_os_string();
let file_name_string_option = fns.to_str();

if let Some(file_name_string) = file_name_string_option {

let file_model = FileModel::new(file_path, file_name_string.to_string(), file.content.clone());
let file_model = FileModel::new(
file_path,
file_name_string.to_string(),
file.content.clone(),
);
file_models.push(file_model);

} else {
error!("Failed to convert file name to string");
}

} else {
error!("Failed to extract file name from path");
}
Expand All @@ -61,12 +62,12 @@ impl InternalApi {

// For each file model, create the directory and the file
file_models.iter().for_each(|file_model| {

let file_path = file_model.path.clone();
let file_name = file_model.file_name.clone();

// Create the directory
let op_dir = std::fs::create_dir_all(&file_path).map_err(|e| anyhow!("Failed to create directory: {}", e));
let op_dir = std::fs::create_dir_all(&file_path)
.map_err(|e| anyhow!("Failed to create directory: {}", e));
if op_dir.is_err() {
error!("Failed to create directory: {:?}", op_dir.err());
} else {
Expand All @@ -75,12 +76,12 @@ impl InternalApi {

// Create the file
let file_path = file_path.join(file_name);
let op_file = File::create(file_path).map_err(|e| anyhow!("Failed to create file: {}", e));
let op_file =
File::create(file_path).map_err(|e| anyhow!("Failed to create file: {}", e));

if let Err(e) = op_file {
error!("Failed to create file: {:?}", e);
} else {

let mut file = op_file.unwrap();
info!("File created: {:?}", file);

Expand All @@ -92,17 +93,12 @@ impl InternalApi {
} else {
info!("File written: {:?}", file);
}


}


});

Ok(())
}


pub fn write_log(&self) -> String {
"Hello".to_string()
}
Expand Down
Loading

0 comments on commit a809be2

Please sign in to comment.