Skip to content

Commit

Permalink
Fixes #26340: Write a new test framework for the Rudder methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Fdall committed Feb 12, 2025
1 parent 467186f commit a801eed
Show file tree
Hide file tree
Showing 25 changed files with 952 additions and 16 deletions.
41 changes: 41 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = ["policies/rudderc",
"policies/rudder-commons-test",
"policies/rudder-report",
"policies/module-types/*",
"policies/lib",
"relay/sources/relayd",
"relay/sources/rudder-package"]
resolver = "2"
Expand Down
23 changes: 23 additions & 0 deletions policies/lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "lib"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1", features = ["derive"] }
rudderc = { path = "../rudderc" }
rudder_commons = { path = "../rudder-commons" }
tempfile = "3.14.0"
anyhow = "1.0.93"
serde_json = "1.0.133"
dyn-clone = "1.0.18"
log = "0.4.22"
itertools = "0.14.0"
test-log = "*"
serde_yaml = "0.9.34+deprecated"
env_logger = "0.11.6"
regex = "1.11.1"

[dev-dependencies]
test-log = "*"
1 change: 1 addition & 0 deletions policies/lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

70 changes: 70 additions & 0 deletions policies/lib/tests/integration/command_execution_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::integration::{end_test, get_lib_path, init_test};
use crate::testlib::method_test_suite::MethodTestSuite;
use crate::testlib::method_to_test::{MethodStatus, MethodToTest};

#[test]
fn it_is_not_applicable_in_audit_mode() {
let workdir = init_test();
let file_path = workdir.path().join("target.txt");

let tested_method = MethodToTest::command_execution(format!(
"/bin/touch {}",
file_path.clone().to_str().unwrap()
))
.audit();
let r = MethodTestSuite::new()
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method.clone(), vec![MethodStatus::NA]);
r.assert_log_v4_result_conditions(tested_method.clone(), MethodStatus::NA);
assert!(
!file_path.exists(),
"The file '{}' should not have been created by the method execution",
file_path.display()
);
end_test(workdir);
}
#[test]
fn it_repairs_in_enforced_mode_if_the_command_succeeds() {
let workdir = init_test();
let file_path = workdir.path().join("target.txt");

let tested_method = MethodToTest::command_execution(format!(
"/bin/touch {}",
file_path.clone().to_str().unwrap()
))
.enforce();
let r = MethodTestSuite::new()
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method.clone(), vec![MethodStatus::Repaired]);
r.assert_log_v4_result_conditions(tested_method.clone(), MethodStatus::Repaired);
assert!(
file_path.exists(),
"The file '{}' should have been created by the method execution",
file_path.display()
);
end_test(workdir);
}
#[test]
fn it_errors_in_enforced_mode_if_the_command_fails() {
let workdir = init_test();
let file_path = workdir.path().join("nonexistingfolder/target.txt");

let tested_method = MethodToTest::command_execution(format!(
"/bin/touch {}",
file_path.clone().to_str().unwrap()
))
.enforce();
let r = MethodTestSuite::new()
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method.clone(), vec![MethodStatus::Error]);
r.assert_log_v4_result_conditions(tested_method.clone(), MethodStatus::Error);
assert!(
!file_path.exists(),
"The file '{}' should not have been created by the method execution",
file_path.display()
);
end_test(workdir);
}
94 changes: 94 additions & 0 deletions policies/lib/tests/integration/file_absent_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use crate::integration::{end_test, get_lib_path, init_test};
use crate::testlib::given::Given;
use crate::testlib::method_test_suite::MethodTestSuite;
use crate::testlib::method_to_test::{MethodStatus, MethodToTest};

#[test]
fn it_repairs_in_enforce_when_the_target_file_exists() {
let workdir = init_test();
let file = workdir.path().join("file_to_remove");
let file_path = file.clone().to_string_lossy().into_owned();

let tested_method = MethodToTest::file_absent(file_path.clone()).enforce();
let r = MethodTestSuite::new()
.given(Given::file_present(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Repaired]);
assert!(
!file.exists(),
"The file '{}' should have been removed by the method execution",
file.display()
);
end_test(workdir);
}

#[test]
fn it_errors_in_audit_when_the_target_file_exists() {
let workdir = init_test();
let file = workdir.path().join("file_to_remove");
let file_path = file.clone().to_string_lossy().into_owned();

let tested_method = MethodToTest::file_absent(file_path.clone()).audit();
let r = MethodTestSuite::new()
.given(Given::file_present(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Error]);
assert!(
file.exists(),
"The file '{}' should NOT have been removed by the method execution",
file.display()
);
end_test(workdir);
}

#[test]
fn it_errors_in_enforce_when_the_target_exists_and_is_a_directory() {
let workdir = init_test();
let dir = workdir.path().join("dir_to_remove");
let file_path = dir.clone().to_string_lossy().into_owned();
let tested_method = MethodToTest::file_absent(file_path.clone()).enforce();

let r = MethodTestSuite::new()
.given(Given::directory_present(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Error]);
assert!(
dir.exists(),
"The directory '{}' should not have been removed by the method execution",
dir.display()
);
end_test(workdir);
}

#[ignore]
#[test_log::test]
fn it_should_be_idempotent() {
let workdir = init_test();
let file = workdir.path().join("file_to_remove");
let file_path = file.clone().to_string_lossy().into_owned();
let tested_method = MethodToTest::file_absent(file_path.clone()).enforce();

let r = MethodTestSuite::new()
.given(Given::file_present(file_path.clone()))
.when(tested_method.clone())
.when(tested_method.clone())
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(
tested_method,
vec![
MethodStatus::Repaired,
MethodStatus::Success,
MethodStatus::Success,
],
);
assert!(
!file.exists(),
"The file '{}' should have been removed by the method execution",
file.display()
);
end_test(workdir);
}
92 changes: 92 additions & 0 deletions policies/lib/tests/integration/file_check_exists_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::integration::{end_test, get_lib_path, init_test};
use crate::testlib::given::Given;
use crate::testlib::method_test_suite::MethodTestSuite;
use crate::testlib::method_to_test::{MethodStatus, MethodToTest};

#[test]
fn it_succeeds_in_enforce_when_the_target_file_exists() {
let workdir = init_test();
let file_path = workdir
.path()
.join("flag_file")
.to_string_lossy()
.into_owned();
let tested_method = MethodToTest::file_check_exists(file_path.clone()).enforce();

let r = MethodTestSuite::new()
.given(Given::file_present(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Success]);
end_test(workdir);
}

#[test]
fn it_fails_in_enforce_when_the_target_file_does_not_exist() {
let workdir = init_test();
let file_path = workdir
.path()
.join("flag_file")
.to_string_lossy()
.into_owned();

let tested_method = MethodToTest::file_check_exists(file_path.clone()).enforce();
let r = MethodTestSuite::new()
.given(Given::file_absent(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Error]);
end_test(workdir);
}

#[test]
fn it_succeeds_in_audit_when_the_target_file_exists() {
let workdir = init_test();
let file_path = workdir
.path()
.join("flag_file")
.to_string_lossy()
.into_owned();

let tested_method = MethodToTest::file_check_exists(file_path.clone()).audit();
let r = MethodTestSuite::new()
.given(Given::file_present(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Success]);
end_test(workdir);
}
#[test]
fn it_succeeds_in_audit_when_the_target_file_does_not_exist() {
let workdir = init_test();
let file_path = workdir
.path()
.join("flag_file")
.to_string_lossy()
.into_owned();

let tested_method = MethodToTest::file_check_exists(file_path.clone()).audit();
let r = MethodTestSuite::new()
.given(Given::file_absent(file_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Error]);
end_test(workdir);
}
#[test]
fn it_succeeds_in_enforce_when_the_target_is_a_directory() {
let workdir = init_test();
let dir_path = workdir
.path()
.join("directory")
.to_string_lossy()
.into_owned();

let tested_method = MethodToTest::file_check_exists(dir_path.clone()).audit();
let r = MethodTestSuite::new()
.given(Given::directory_present(dir_path.clone()))
.when(tested_method.clone())
.execute(get_lib_path(), workdir.path().to_path_buf());
r.assert_legacy_result_conditions(tested_method, vec![MethodStatus::Success]);
end_test(workdir);
}
36 changes: 36 additions & 0 deletions policies/lib/tests/integration/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#[cfg(test)]
pub mod command_execution_test;
#[cfg(test)]
pub mod file_absent_test;
#[cfg(test)]
pub mod file_check_exists_test;
use log::debug;
use rudder_commons::methods::Methods;
use std::mem::ManuallyDrop;
use std::path::PathBuf;
use std::sync::OnceLock;
use tempfile::{tempdir, TempDir};

const LIBRARY_PATH: &str = "./tree";
pub fn get_lib() -> &'static Methods {
static LIB: OnceLock<Methods> = OnceLock::new();
LIB.get_or_init(|| {
rudderc::frontends::read_methods(&[get_lib_path()])
.unwrap()
.clone()
})
}
fn get_lib_path() -> PathBuf {
PathBuf::from(LIBRARY_PATH)
}

fn init_test() -> ManuallyDrop<TempDir> {
env_logger::init();
let workdir = tempdir().unwrap();
debug!("WORKDIR = {:?}", workdir.path());
ManuallyDrop::new(workdir)
}

fn end_test(workdir: ManuallyDrop<TempDir>) {
ManuallyDrop::into_inner(workdir);
}
2 changes: 2 additions & 0 deletions policies/lib/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod integration;
pub mod testlib;
Loading

0 comments on commit a801eed

Please sign in to comment.