use assert_cmd::prelude::*; use predicates::prelude::*; use std::fs::File; use std::io::prelude::*; use std::process::Command; use tempfile::TempDir; mod common; mod one_one { use super::*; /// Create a simple project with one service and one stage. /// fn create_project( service_name: &str, stage_name: &str, ) -> Result> { // Create a project with a single service let root_dir = common::create_project("one-service-one-stage")?; let folder = root_dir.path(); common::create_service(&folder, &service_name)?; // Update the project config let mut cfg_file = File::create(folder.join("orcs.toml"))?; let cfg_data = format!("[stages.{}]", stage_name); cfg_file.write_all(cfg_data.as_bytes())?; // Update the service config let mut cfg_file = File::create(folder.join("srv").join(&service_name).join("orcs.toml"))?; let cfg_data = format!( "stages.{}.actions = \"echo Hello from $ORCS_SERVICE > $ORCS_ROOT/test.txt\"", stage_name ); cfg_file.write_all(cfg_data.as_bytes())?; Ok(root_dir) } /// Run a project with a single service and stage #[test] fn run_all() -> Result<(), Box> { // Create the project let root_dir = create_project("my-service", "my_stage")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d").arg("-p").arg(&folder).arg("run").arg("all"); cmd.assert().success(); // Check the output file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert!(predicate::str::contains("Hello from my-service").eval(&test_data)); Ok(()) } /// Run the stage of a project with a single service and stage #[test] fn run_stage() -> Result<(), Box> { // Create the project let root_dir = create_project("my-service", "my_stage")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("my_stage"); cmd.assert().success(); // Check the output file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert!(predicate::str::contains("Hello from my-service").eval(&test_data)); Ok(()) } #[test] fn run_stage_service() -> Result<(), Box> { // Create the project let root_dir = create_project("my-service", "my_stage")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("my_stage") .arg("my-service"); cmd.assert().success(); // Check the output file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert!(predicate::str::contains("Hello from my-service").eval(&test_data)); Ok(()) } #[test] fn run_all_failing() -> Result<(), Box> { // Create the project let root_dir = create_project("my-service", "my_stage")?; let folder = root_dir.path(); // Update the service config let mut cfg_file = File::create(folder.join("srv").join("my-service").join("orcs.toml"))?; let cfg_data = "stages.my_stage.actions = \"\"\"false\ntrue\"\"\""; cfg_file.write_all(cfg_data.as_bytes())?; // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d").arg("-p").arg(&folder).arg("run").arg("all"); cmd.assert().failure(); Ok(()) } #[test] fn run_all_output() -> Result<(), Box> { // Create the project let root_dir = create_project("my-service", "my_stage")?; let folder = root_dir.path(); // Update the service config let mut cfg_file = File::create(folder.join("srv").join("my-service").join("orcs.toml"))?; let cfg_data = "stages.my_stage.actions = \"echo Hello from my-service\""; cfg_file.write_all(cfg_data.as_bytes())?; // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d").arg("-p").arg(&folder).arg("run").arg("all"); cmd.assert() .success() .stdout(predicate::str::contains("Hello from my-service")); Ok(()) } } mod two_two { use super::*; /// Create a project with two services and two stages /// /// The 2nd stage depends on the 1st one and the 2nd service depends on the 1st one fn create_project( service1: &str, service2: &str, stage1: &str, stage2: &str, ) -> Result> { // Create a project with two services let root_dir = common::create_project("one-service-one-stage")?; let folder = root_dir.path(); common::create_service(&folder, &service1)?; common::create_service(&folder, &service2)?; // Update the project config let mut cfg_file = File::create(folder.join("orcs.toml"))?; let cfg_data = format!( " [stages.{stage1}] [stages.{stage2}] depends_on = [\"{stage1}\"] ", stage1 = stage1, stage2 = stage2 ); cfg_file.write_all(cfg_data.as_bytes())?; // Update service1 config let mut cfg_file = File::create(folder.join("srv").join(&service1).join("orcs.toml"))?; let cfg_data = format!( " [stages.{stage1}] actions = \"echo Hello1 from $ORCS_SERVICE >> $ORCS_ROOT/test.txt\" check = \"grep 'Hello1 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" [stages.{stage2}] actions = \"echo Hello2 from $ORCS_SERVICE >> $ORCS_ROOT/test.txt\" check = \"grep 'Hello2 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" ", stage1 = stage1, stage2 = stage2 ); cfg_file.write_all(cfg_data.as_bytes())?; // Update service2 config let mut cfg_file = File::create(folder.join("srv").join(&service2).join("orcs.toml"))?; let cfg_data = format!( " [stages.{stage1}] depends_on=[\"{service1}\"] actions = \"echo Hello1 from $ORCS_SERVICE >> $ORCS_ROOT/test.txt\" check = \"grep 'Hello1 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" [stages.{stage2}] depends_on=[\"{service1}\"] actions = \"echo Hello2 from $ORCS_SERVICE >> $ORCS_ROOT/test.txt\" check = [ \"env | grep ORCS\", \"grep 'Hello2 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" ] ", stage1 = stage1, stage2 = stage2, service1 = service1 ); cfg_file.write_all(cfg_data.as_bytes())?; Ok(root_dir) } #[test] fn run_all() -> Result<(), Box> { // If something is wrong, the result is non-deterministic. Therefore run // this enough times to ensure the result is not just a fluke. for _ in 0..50 { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d").arg("-p").arg(&folder).arg("run").arg("all"); cmd.assert().success(); // Check test file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert_eq!("Hello1 from service-a\nHello1 from service-b\nHello2 from service-a\nHello2 from service-b\n", test_data); } Ok(()) } #[test] fn run_stage1() -> Result<(), Box> { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("stage-a"); cmd.assert().success(); // Check test file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert_eq!("Hello1 from service-a\nHello1 from service-b\n", test_data); Ok(()) } #[test] fn run_stage2_fail() -> Result<(), Box> { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("stage-b"); // Expecting a failure as we need to run stage1 first cmd.assert().failure(); Ok(()) } #[test] fn run_stage1_service1() -> Result<(), Box> { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("stage-a") .arg("service-a"); cmd.assert().success(); // Check test file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert_eq!("Hello1 from service-a\n", test_data); Ok(()) } #[test] fn run_stage2_service1_fail() -> Result<(), Box> { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("stage-b") .arg("service-a"); // Expecting failure as we need to run stage-a first cmd.assert().failure(); Ok(()) } #[test] fn run_stage1_service2_fail() -> Result<(), Box> { // Create a project with 2 services let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d") .arg("-p") .arg(&folder) .arg("run") .arg("stage-a") .arg("service-b"); // Expecting failure as we need to run service-a first cmd.assert().failure(); Ok(()) } #[test] fn run_all_failing() -> Result<(), Box> { let root_dir = create_project("service-a", "service-b", "stage-a", "stage-b")?; let folder = root_dir.path(); // Update the config for service B println!("yay"); let mut cfg_file = File::create(folder.join("srv").join("service-b").join("orcs.toml"))?; let cfg_data = " [stages.stage-a] depends_on=[\"service-a\"] actions = \"\"\"false\ntrue\"\"\" check = \"grep 'Hello1 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" [stages.stage-b] depends_on=[\"service-a\"] actions = \"echo Hello2 from $ORCS_SERVICE >> $ORCS_ROOT/test.txt\" check = [ \"env | grep ORCS\", \"grep 'Hello2 from '$ORCS_SERVICE $ORCS_ROOT/test.txt\" ] "; cfg_file.write_all(cfg_data.as_bytes())?; println!("nay"); // Run the command let mut cmd = Command::cargo_bin("orcs")?; cmd.arg("-d").arg("-p").arg(&folder).arg("run").arg("all"); cmd.assert().failure(); // Check test file let mut test_file = File::open(folder.join("test.txt"))?; let mut test_data = String::new(); test_file.read_to_string(&mut test_data)?; assert_eq!("Hello1 from service-a\n", test_data); Ok(()) } }