use csml_engine::{ data::{BotOpt, CsmlRequest}, delete_client, start_conversation, }; use csml_interpreter::data::{csml_bot::CsmlBot, csml_flow::CsmlFlow, Client}; use serde::{Deserialize, Serialize}; use serde_json::json; use std::fs; use std::io::prelude::*; use std::path::Path; use uuid::Uuid; #[derive(Debug, Clone, Serialize, Deserialize)] struct FlowInfo { name: String, description: Option, commands: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] struct BotInfo { id: String, name: String, description: Option, default_flow: String, flows: Vec, files: Vec, functions: Vec, apps: Vec, } fn get_commands(name: &str, bot_info: &BotInfo) -> Vec { for flow in &bot_info.flows { if flow.name == name { return flow.commands.to_owned(); } } vec![] } fn init_bot(bot_name: &str) -> Result { let mut bot_flows = vec![]; let tmp = format!("CSML/test/{}/flows", bot_name); let flows_path = Path::new(&tmp); let mut file = fs::File::open(&format!("CSML/test/{}/bot.json", bot_name))?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let bot_info: BotInfo = serde_json::from_str(&contents).unwrap(); for flow in fs::read_dir(flows_path)? { let flow = flow?; let mut flow_file = fs::File::open(flow.path().to_str().unwrap())?; let mut flow_content = String::new(); flow_file.read_to_string(&mut flow_content)?; let name = flow .file_name() .to_str() .unwrap() .trim_end_matches(".csml") .to_owned(); let commands = get_commands(&name, &bot_info); bot_flows.push(CsmlFlow { id: name.to_owned(), name: name.to_owned(), commands, content: flow_content, }); } let bot = CsmlBot { id: bot_info.name.clone(), name: bot_info.name.clone(), apps_endpoint: None, flows: bot_flows, native_components: None, custom_components: None, default_flow: bot_info.default_flow.clone(), bot_ast: None, no_interruption_delay: None, env: Some(serde_json::json!({ "random": "value", "toto": "key", })), modules: None, multibot: None, }; Ok(bot) } fn init_request(string: &str, bot_id: String, channel_id: String) -> CsmlRequest { CsmlRequest { request_id: "tmp".to_owned(), client: Client { user_id: "test".to_owned(), bot_id, channel_id, }, callback_url: Some("http://httpbin.org/post".to_owned()), payload: json!({ "content_type": "text", "content": { "text": string}, }), metadata: json!({"some": "custom-value"}), ttl_duration: None, step_limit: None, low_data_mode: None, } } #[test] fn ok_test_hold() { let bot = init_bot("goto_flow").unwrap(); let events = &["start", "hold", "event1", "event2", "event3"]; let messages = &[ "start", "hold", "start[1]", "end[1]:event1", "start[2]", "end[2]:event2", "start[3]", "end[3]:event3", ]; let channel_id = Uuid::new_v4().to_string(); let bot_id = match std::env::var("GITHUB_SHA") { Ok(mut value) => { let id = Uuid::new_v4().to_string(); value.push_str(&id); value } Err(..) => Uuid::new_v4().to_string(), }; let mut output_message = vec![]; for event in events.iter() { match start_conversation( init_request(event, bot_id.clone(), channel_id.clone()), BotOpt::CsmlBot(bot.to_owned()), ) { Ok(obj) => { let messages = obj["messages"].as_array().unwrap(); for message in messages.iter() { output_message.push( message["payload"]["content"]["text"] .as_str() .unwrap() .to_owned(), ); } if obj["conversation_end"].as_bool().unwrap() { break; } } Err(err) => { println!("{:?}", err); break; } } } if output_message != messages { panic!("\noutput {:?}\n message {:?}", output_message, messages); } delete_client(&Client { user_id: "test".to_owned(), bot_id: bot_id.clone(), channel_id: channel_id.clone(), }) .unwrap(); } #[test] fn ok_test_import() { let bot = init_bot("goto_flow").unwrap(); let events = &["goto flow3"]; let messages = &["hello from fn"]; let channel_id = Uuid::new_v4().to_string(); let bot_id = match std::env::var("GITHUB_SHA") { Ok(mut value) => { let id = Uuid::new_v4().to_string(); value.push_str(&id); value } Err(..) => Uuid::new_v4().to_string(), }; let mut output_message = vec![]; for event in events.iter() { match start_conversation( init_request(event, bot_id.clone(), channel_id.clone()), BotOpt::CsmlBot(bot.to_owned()), ) { Ok(obj) => { let messages = obj["messages"].as_array().unwrap(); for message in messages.iter() { output_message.push( message["payload"]["content"]["text"] .as_str() .unwrap() .to_owned(), ); } if obj["conversation_end"].as_bool().unwrap() { break; } } Err(err) => { println!("{:?}", err); break; } } } if output_message != messages { panic!("\noutput {:?}\n message {:?}", output_message, messages); } delete_client(&Client { user_id: "test".to_owned(), bot_id: bot_id.clone(), channel_id: channel_id.clone(), }) .unwrap(); } #[test] fn ok_test_commands() { let bot = init_bot("goto_flow").unwrap(); let events = &["/flow4"]; let messages = &["flow4"]; let channel_id = Uuid::new_v4().to_string(); let bot_id = match std::env::var("GITHUB_SHA") { Ok(mut value) => { let id = Uuid::new_v4().to_string(); value.push_str(&id); value } Err(..) => Uuid::new_v4().to_string(), }; let mut output_message = vec![]; for event in events.iter() { match start_conversation( init_request(event, bot_id.clone(), channel_id.clone()), BotOpt::CsmlBot(bot.to_owned()), ) { Ok(obj) => { let messages = obj["messages"].as_array().unwrap(); for message in messages.iter() { output_message.push( message["payload"]["content"]["text"] .as_str() .unwrap() .to_owned(), ); } if obj["conversation_end"].as_bool().unwrap() { break; } } Err(err) => { println!("{:?}", err); break; } } } if output_message != messages { panic!("\noutput {:?}\n message {:?}", output_message, messages); } delete_client(&Client { user_id: "test".to_owned(), bot_id: bot_id.clone(), channel_id: channel_id.clone(), }) .unwrap(); } #[test] fn ok_test_goto_var() { let bot = init_bot("goto_flow").unwrap(); let events = &["/flow5"]; let messages = &["flow5 start", "flow5 step1", "flow4"]; let channel_id = Uuid::new_v4().to_string(); let bot_id = match std::env::var("GITHUB_SHA") { Ok(mut value) => { let id = Uuid::new_v4().to_string(); value.push_str(&id); value } Err(..) => Uuid::new_v4().to_string(), }; let mut output_message = vec![]; for event in events.iter() { match start_conversation( init_request(event, bot_id.clone(), channel_id.clone()), BotOpt::CsmlBot(bot.to_owned()), ) { Ok(obj) => { let messages = obj["messages"].as_array().unwrap(); for message in messages.iter() { output_message.push( message["payload"]["content"]["text"] .as_str() .unwrap() .to_owned(), ); } if obj["conversation_end"].as_bool().unwrap() { break; } } Err(err) => { println!("{:?}", err); break; } } } if output_message != messages { panic!("\noutput {:?}\n message {:?}", output_message, messages); } delete_client(&Client { user_id: "test".to_owned(), bot_id: bot_id.clone(), channel_id: channel_id.clone(), }) .unwrap(); } #[test] fn ok_test_memory() { let bot = init_bot("goto_flow").unwrap(); let events = &["/flow6"]; let messages = &[ "flow6 start", "< random > is used before it was saved in memory at line 8, column 30 at flow [flow6]", "{\"val\":1}", "message", "4", "4.2", "[21,42,84]", "< random > is used before it was saved in memory at line 17, column 9 at flow [flow6]", "Null", ]; let channel_id = Uuid::new_v4().to_string(); let bot_id = match std::env::var("GITHUB_SHA") { Ok(mut value) => { let id = Uuid::new_v4().to_string(); value.push_str(&id); value } Err(..) => Uuid::new_v4().to_string(), }; let mut output_message = vec![]; for event in events.iter() { match start_conversation( init_request(event, bot_id.clone(), channel_id.clone()), BotOpt::CsmlBot(bot.to_owned()), ) { Ok(obj) => { let messages = obj["messages"].as_array().unwrap(); for message in messages.iter() { let content_type = message["payload"]["content_type"].as_str().unwrap(); output_message.push( message["payload"]["content"][content_type] .as_str() .unwrap_or("Null") .to_owned(), ); } if obj["conversation_end"].as_bool().unwrap() { break; } } Err(err) => { println!("{:?}", err); break; } } } if output_message != messages { panic!("\noutput {:?}\n messages {:?}", output_message, messages); } delete_client(&Client { user_id: "test".to_owned(), bot_id: bot_id.clone(), channel_id: channel_id.clone(), }) .unwrap(); }