Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add kill test #2996

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tests/contest/contest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::tests::hooks::get_hooks_tests;
use crate::tests::hostname::get_hostname_test;
use crate::tests::intel_rdt::get_intel_rdt_test;
use crate::tests::io_priority::get_io_priority_test;
use crate::tests::kill::get_kill_test;
use crate::tests::lifecycle::{ContainerCreate, ContainerLifecycle};
use crate::tests::linux_ns_itype::get_ns_itype_tests;
use crate::tests::mounts_recursive::get_mounts_recursive_test;
Expand Down Expand Up @@ -125,6 +126,7 @@ fn main() -> Result<()> {
let process_rlimtis = get_process_rlimits_test();
let no_pivot = get_no_pivot_test();
let process_oom_score_adj = get_process_oom_score_adj_test();
let kill = get_kill_test();

tm.add_test_group(Box::new(cl));
tm.add_test_group(Box::new(cc));
Expand Down Expand Up @@ -154,6 +156,7 @@ fn main() -> Result<()> {
tm.add_test_group(Box::new(process_rlimtis));
tm.add_test_group(Box::new(no_pivot));
tm.add_test_group(Box::new(process_oom_score_adj));
tm.add_test_group(Box::new(kill));

tm.add_test_group(Box::new(io_priority_test));
tm.add_cleanup(Box::new(cgroups::cleanup_v1));
Expand Down
146 changes: 146 additions & 0 deletions tests/contest/contest/src/tests/kill/kill_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::time::Duration;

use anyhow::{anyhow, Context, Result};
use oci_spec::runtime::{ProcessBuilder, Spec, SpecBuilder};
use test_framework::{Test, TestGroup, TestResult};

use crate::tests::lifecycle::ContainerLifecycle;

fn create_spec(args: &[&str]) -> Result<Spec> {
let args_vec: Vec<String> = args.iter().map(|&a| a.to_string()).collect();
let spec = SpecBuilder::default()
.process(
ProcessBuilder::default()
.args(args_vec)
.build()
.context("failed to build process spec")?,
)
.build()
.context("failed to build spec")?;
Ok(spec)
}

fn kill_with_empty_id_test() -> TestResult {
let mut container = ContainerLifecycle::new();

// kill with empty id
container.set_id("");
let result = match container.kill() {
TestResult::Failed(_) => TestResult::Passed,
TestResult::Passed => TestResult::Failed(anyhow!(
"Expected killing container with empty id to fail, but was successful"
)),
_ => TestResult::Failed(anyhow!(
"Unexpected killing container with empty id test result"
)),
};
container.delete();
result
}

fn kill_non_existed_container() -> TestResult {
let mut container = ContainerLifecycle::new();

// kill for non existed container
container.set_id("non-existent-container-id");
let result = match container.kill() {
TestResult::Failed(_) => TestResult::Passed,
TestResult::Passed => TestResult::Failed(anyhow!(
"Expected killing non existed container to fail, but was successful"
)),
_ => TestResult::Failed(anyhow!(
"Unexpected killing non existed container test result"
)),
};
container.delete();
result
}
fn kill_created_container_test() -> TestResult {
let container = ContainerLifecycle::new();

// kill created container
match container.create() {
TestResult::Passed => {}
_ => return TestResult::Failed(anyhow!("Failed to create container")),
}
let result = container.kill();
container.delete();
result
}

fn kill_stopped_container_test() -> TestResult {
let container = ContainerLifecycle::new();
let spec = create_spec(&["true"]).unwrap();

// kill stopped container
match container.create_with_spec(spec) {
TestResult::Passed => {}
_ => return TestResult::Failed(anyhow!("Failed to create container")),
}
match container.start() {
TestResult::Passed => {}
_ => return TestResult::Failed(anyhow!("Failed to start container")),
}
container.waiting_for_status(Duration::from_secs(10), Duration::from_secs(1), "stopped");
let result = match container.kill() {
TestResult::Failed(_) => TestResult::Passed,
TestResult::Passed => TestResult::Failed(anyhow!("Expected failure but got success")),
_ => TestResult::Failed(anyhow!("Unexpected test result")),
};
container.delete();
result
}

fn kill_start_container_test() -> TestResult {
let container = ContainerLifecycle::new();
let spec = create_spec(&["sleep", "30"]).unwrap();

// kill start container
match container.create_with_spec(spec) {
TestResult::Passed => {}
_ => return TestResult::Failed(anyhow!("Failed to recreate container")),
}

match container.start() {
TestResult::Passed => {}
TestResult::Failed(err) => {
return TestResult::Failed(anyhow!("Failed to start container: {:?}", err));
}
_ => unreachable!(),
}
container.waiting_for_status(Duration::from_secs(10), Duration::from_secs(1), "running");
let result = container.kill();
container.delete();
result
}

pub fn get_kill_test() -> TestGroup {
let mut test_group = TestGroup::new("kill_container");

let kill_with_empty_id_test =
Test::new("kill_with_empty_id_test", Box::new(kill_with_empty_id_test));
let kill_non_existed_container = Test::new(
"kill_non_existed_container",
Box::new(kill_non_existed_container),
);
let kill_created_container_test = Test::new(
"kill_created_container_test",
Box::new(kill_created_container_test),
);
let kill_stopped_container_test = Test::new(
"kill_stopped_container_test",
Box::new(kill_stopped_container_test),
);
let kill_start_container_test = Test::new(
"kill_start_container_test",
Box::new(kill_start_container_test),
);
test_group.add(vec![
Box::new(kill_with_empty_id_test),
Box::new(kill_non_existed_container),
Box::new(kill_created_container_test),
Box::new(kill_stopped_container_test),
Box::new(kill_start_container_test),
]);
test_group
}
3 changes: 3 additions & 0 deletions tests/contest/contest/src/tests/kill/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod kill_test;

pub use kill_test::get_kill_test;
44 changes: 42 additions & 2 deletions tests/contest/contest/src/tests/lifecycle/container_lifecycle.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::thread::sleep;
use std::time::Duration;
use std::time::{Duration, Instant};

use anyhow::anyhow;
use oci_spec::runtime::Spec;
use test_framework::{TestResult, TestableGroup};

use super::util::criu_installed;
use super::{checkpoint, create, delete, exec, kill, start, state};
use crate::utils::{generate_uuid, prepare_bundle};
use crate::utils::{generate_uuid, get_state, prepare_bundle, set_config, State};

// By experimenting, somewhere around 50 is enough for youki process
// to get the kill signal and shut down
Expand Down Expand Up @@ -33,10 +35,23 @@ impl ContainerLifecycle {
}
}

pub fn set_id(&mut self, id: &str) {
self.container_id = id.to_string();
}

pub fn get_id(&self) -> &str {
&self.container_id
}

pub fn create(&self) -> TestResult {
create::create(self.project_path.path(), &self.container_id).into()
}

pub fn create_with_spec(&self, spec: Spec) -> TestResult {
set_config(&self.project_path, &spec).unwrap();
create::create(self.project_path.path(), &self.container_id).into()
}

#[allow(dead_code)]
pub fn exec(&self, cmd: Vec<&str>, expected_output: Option<&str>) -> TestResult {
exec::exec(
Expand Down Expand Up @@ -86,6 +101,31 @@ impl ContainerLifecycle {
&self.container_id,
)
}

pub fn waiting_for_status(
&self,
retry_timeout: Duration,
poll_interval: Duration,
target_status: &str,
) -> TestResult {
let start = Instant::now();
while start.elapsed() < retry_timeout {
let (out, err) = get_state(&self.container_id, &self.project_path).unwrap();
if !err.is_empty() {
self.kill();
self.delete();
return TestResult::Failed(anyhow!("error in state : {}", err));
}

let state: State = serde_json::from_str(&out).unwrap();

if state.status == target_status {
return TestResult::Passed;
}
sleep(poll_interval);
}
TestResult::Failed(anyhow!("error pod status is not update"))
}
}

impl TestableGroup for ContainerLifecycle {
Expand Down
1 change: 1 addition & 0 deletions tests/contest/contest/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod hooks;
pub mod hostname;
pub mod intel_rdt;
pub mod io_priority;
pub mod kill;
pub mod lifecycle;
pub mod linux_ns_itype;
pub mod mounts_recursive;
Expand Down
Loading