#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::items_after_statements,
clippy::unnecessary_wraps,
clippy::no_effect_underscore_binding
)]
mod tests {
use crate::chain::Chain;
use crate::executor::ExecutionResult;
use crate::tests::mock_executor::MockExecutor;
#[test]
fn test_exported_types() {
use crate::{AtentoError, DataType, Result};
let _dt: DataType = DataType::String;
let _err: AtentoError = AtentoError::Validation("test".to_string());
fn test_result() -> Result<()> {
Ok(())
}
assert!(test_result().is_ok());
}
#[test]
fn test_run_chain_multiple_outputs() {
let yaml = r"
name: multi_output_chain
steps:
step1:
type: bash
script: |
echo 'name: Alice'
echo 'age: 25'
outputs:
name:
pattern: 'name: (\w+)'
type: string
age:
pattern: 'age: (\d+)'
type: int
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'name: Alice'\necho 'age: 25'\n",
ExecutionResult {
stdout: "name: Alice\\nage: 25\\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
assert_eq!(result.name, Some("multi_output_chain".to_string()));
}
#[test]
fn test_run_chain_with_all_data_types() {
let yaml = r#"
name: all_types_chain
parameters:
str_param:
type: string
value: hello
int_param:
type: int
value: 42
float_param:
type: float
value: 3.14
bool_param:
type: bool
value: true
date_param:
type: datetime
value: "2024-01-15T10:30:00Z"
steps:
step1:
type: bash
script: echo ok
"#;
let mut mock = MockExecutor::new();
mock.expect_call(
"echo ok\n",
ExecutionResult {
stdout: "ok\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_simple_chain() {
let yaml = r"
name: test_chain
steps:
step1:
type: bash
script: echo hello
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo hello\n",
ExecutionResult {
stdout: "hello\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_with_parameter() {
let yaml = r"
name: param_chain
parameters:
greeting:
type: string
value: hello
steps:
step1:
type: bash
script: echo {{ inputs.msg }}
inputs:
msg:
ref: parameters.greeting
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo hello\n",
ExecutionResult {
stdout: "hello\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_with_output() {
let yaml = r"
name: output_chain
steps:
step1:
type: bash
script: |
echo 'result: 42'
outputs:
value:
pattern: 'result: (\d+)'
type: int
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'result: 42'\n",
ExecutionResult {
stdout: "result: 42\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_with_results() {
let yaml = r"
name: result_chain
steps:
step1:
type: bash
script: |
echo 'status: success'
outputs:
status:
pattern: 'status: (\w+)'
type: string
results:
final_status:
ref: steps.step1.outputs.status
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'status: success'\n",
ExecutionResult {
stdout: "status: success\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_step_chaining() {
let yaml = r"
name: chain_chain
steps:
step1:
type: bash
script: |
echo 'value: 100'
outputs:
num:
pattern: 'value: (\d+)'
type: int
step2:
type: bash
script: |
echo {{ inputs.prev }}
inputs:
prev:
ref: steps.step1.outputs.num
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'value: 100'\n",
ExecutionResult {
stdout: "value: 100\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
mock.expect_call(
"echo 100\n",
ExecutionResult {
stdout: "100\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 30,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
assert_eq!(result.name, Some("chain_chain".to_string()));
}
#[test]
fn test_run_chain_execution_error() {
let yaml = r"
name: error_chain
steps:
step1:
type: bash
script: echo 'no match'
outputs:
value:
pattern: 'result: (\d+)'
type: int
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'no match'\n",
ExecutionResult {
stdout: "no match\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "nok");
assert!(!result.errors.is_empty());
}
#[test]
fn test_run_chain_timeout() {
use crate::tests::mock_executor::MockExecutor;
let yaml = r"
name: timeout_chain
timeout: 1
steps:
step1:
type: bash
script: |
sleep 2
";
let mut mock = MockExecutor::new();
mock.expect_timeout("sleep 2\n");
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_with_extremely_long_output() {
let yaml = r#"
name: long_output_chain
steps:
step1:
type: bash
script: |
# Generate a very long string for testing JSON serialization limits
for i in {1..1000}; do echo -n "A"; done
echo ""
outputs:
value:
pattern: '(A+)'
type: string
"#;
let mut mock = MockExecutor::new();
let long_output = "A".repeat(1000) + "\n";
mock.expect_call(
"# Generate a very long string for testing JSON serialization limits\nfor i in {1..1000}; do echo -n \"A\"; done\necho \"\"\n",
ExecutionResult {
stdout: long_output,
stderr: String::new(),
exit_code: 0,
duration_ms: 100,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_chain_with_unicode_characters() {
let yaml = r"
name: unicode_chain
steps:
step1:
type: bash
script: |
echo 'result: こんにちは世界 🌍'
outputs:
value:
pattern: 'result: (.*)'
type: string
";
let mut mock = MockExecutor::new();
mock.expect_call(
"echo 'result: こんにちは世界 🌍'\n",
ExecutionResult {
stdout: "result: こんにちは世界 🌍\n".to_string(),
stderr: String::new(),
exit_code: 0,
duration_ms: 50,
},
);
let chain: Chain = serde_yaml::from_str(yaml).unwrap();
let result = chain.run_with_executor(&mock);
assert_eq!(result.status, "ok");
}
#[test]
fn test_run_function_with_nonexistent_file() {
let result = crate::run("nonexistent_file_12345.yaml");
assert!(result.is_err());
if let Err(crate::AtentoError::Io { path, .. }) = result {
assert_eq!(path, "nonexistent_file_12345.yaml");
} else {
panic!("Expected Io error");
}
}
#[test]
fn test_run_function_with_invalid_yaml() {
use std::io::Write;
let mut temp_file = tempfile::NamedTempFile::new().unwrap();
temp_file.write_all(b"invalid: yaml: {").unwrap();
temp_file.flush().unwrap();
let path = temp_file.path().to_str().unwrap();
let result = crate::run(path);
assert!(result.is_err());
if let Err(crate::AtentoError::YamlParse { context, .. }) = result {
assert!(context.contains(path));
} else {
panic!("Expected YamlParse error");
}
}
#[test]
fn test_run_function_with_validation_error() {
use std::io::Write;
let yaml = r"
name: invalid_chain
steps:
step1:
type: bash
script: echo {{ inputs.missing }}
";
let mut temp_file = tempfile::NamedTempFile::new().unwrap();
temp_file.write_all(yaml.as_bytes()).unwrap();
temp_file.flush().unwrap();
let path = temp_file.path().to_str().unwrap();
let result = crate::run(path);
assert!(result.is_err());
assert!(matches!(result, Err(crate::AtentoError::Validation(_))));
}
#[test]
fn test_run_function_with_successful_chain() {
use std::io::Write;
let yaml = r"
name: simple_chain
steps:
step1:
type: bash
script: echo success
";
let mut temp_file = tempfile::NamedTempFile::new().unwrap();
temp_file.write_all(yaml.as_bytes()).unwrap();
temp_file.flush().unwrap();
let path = temp_file.path().to_str().unwrap();
let result = crate::run(path);
assert!(result.is_ok() || result.is_err());
}
}