use super::ops::{CgroupDef, Op};
use crate::test_support::Payload;
#[derive(Debug, Default)]
pub struct Backdrop {
pub cgroups: Vec<CgroupDef>,
pub payloads: Vec<&'static Payload>,
pub ops: Vec<Op>,
}
impl Backdrop {
pub const EMPTY: Backdrop = Backdrop {
cgroups: Vec::new(),
payloads: Vec::new(),
ops: Vec::new(),
};
#[must_use = "dropping a Backdrop discards the scenario layout"]
pub fn new() -> Self {
Backdrop::EMPTY
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_cgroup(mut self, def: CgroupDef) -> Self {
self.cgroups.push(def);
self
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_cgroups<I: IntoIterator<Item = CgroupDef>>(mut self, defs: I) -> Self {
self.cgroups.extend(defs);
self
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_payload(mut self, payload: &'static Payload) -> Self {
self.payloads.push(payload);
self
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_payloads<I: IntoIterator<Item = &'static Payload>>(mut self, payloads: I) -> Self {
self.payloads.extend(payloads);
self
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_op(mut self, op: Op) -> Self {
self.ops.push(op);
self
}
#[must_use = "builder methods consume self; bind the result"]
pub fn with_ops<I: IntoIterator<Item = Op>>(mut self, ops: I) -> Self {
self.ops.extend(ops);
self
}
pub fn is_empty(&self) -> bool {
self.cgroups.is_empty() && self.payloads.is_empty() && self.ops.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::{OutputFormat, PayloadKind};
const TEST_PAYLOAD: Payload = Payload {
name: "test_bin",
kind: PayloadKind::Binary("/bin/true"),
output: OutputFormat::ExitCode,
default_args: &[],
default_checks: &[],
metrics: &[],
include_files: &[],
uses_parent_pgrp: false,
known_flags: None,
metric_bounds: None,
};
#[test]
fn empty_backdrop_has_no_entities() {
let b = Backdrop::EMPTY;
assert!(b.cgroups.is_empty());
assert!(b.payloads.is_empty());
assert!(b.ops.is_empty());
assert!(b.is_empty());
}
#[test]
fn new_returns_empty() {
let b = Backdrop::new();
assert!(b.is_empty());
}
#[test]
fn with_cgroup_appends_and_loses_empty() {
let b = Backdrop::new().with_cgroup(CgroupDef::named("cg0"));
assert_eq!(b.cgroups.len(), 1);
assert_eq!(b.cgroups[0].name.as_ref(), "cg0");
assert!(!b.is_empty());
}
#[test]
fn with_cgroups_appends_several() {
let b = Backdrop::new().with_cgroups([
CgroupDef::named("cg0"),
CgroupDef::named("cg1"),
CgroupDef::named("cg2"),
]);
assert_eq!(b.cgroups.len(), 3);
assert_eq!(b.cgroups[0].name.as_ref(), "cg0");
assert_eq!(b.cgroups[2].name.as_ref(), "cg2");
}
#[test]
fn with_payload_appends() {
let b = Backdrop::new().with_payload(&TEST_PAYLOAD);
assert_eq!(b.payloads.len(), 1);
assert_eq!(b.payloads[0].name, "test_bin");
assert!(!b.is_empty());
}
#[test]
fn with_payloads_extends_in_order() {
let b = Backdrop::new().with_payloads([&TEST_PAYLOAD, &TEST_PAYLOAD]);
assert_eq!(b.payloads.len(), 2);
assert_eq!(b.payloads[0].name, "test_bin");
assert_eq!(b.payloads[1].name, "test_bin");
}
#[test]
fn with_payloads_appends_after_with_payload() {
let b = Backdrop::new()
.with_payload(&TEST_PAYLOAD)
.with_payloads([&TEST_PAYLOAD]);
assert_eq!(b.payloads.len(), 2);
}
#[test]
fn chain_builds_in_order() {
let b = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_a"))
.with_payload(&TEST_PAYLOAD)
.with_cgroup(CgroupDef::named("cg_b"));
assert_eq!(b.cgroups.len(), 2);
assert_eq!(b.cgroups[0].name.as_ref(), "cg_a");
assert_eq!(b.cgroups[1].name.as_ref(), "cg_b");
assert_eq!(b.payloads.len(), 1);
assert!(!b.is_empty());
}
#[test]
fn default_impl_matches_empty() {
let d: Backdrop = Default::default();
assert!(d.is_empty());
assert_eq!(d.cgroups.len(), Backdrop::EMPTY.cgroups.len());
assert_eq!(d.payloads.len(), Backdrop::EMPTY.payloads.len());
assert_eq!(d.ops.len(), Backdrop::EMPTY.ops.len());
}
#[test]
fn with_op_appends_and_loses_empty() {
let b = Backdrop::new().with_op(Op::add_cgroup("empty_target"));
assert_eq!(b.ops.len(), 1);
assert!(matches!(&b.ops[0], Op::AddCgroup { name } if name.as_ref() == "empty_target"));
assert!(!b.is_empty());
}
#[test]
fn with_ops_appends_several_in_order() {
let b = Backdrop::new().with_ops(vec![Op::add_cgroup("cg_1"), Op::add_cgroup("cg_1/sub")]);
assert_eq!(b.ops.len(), 2);
assert!(matches!(&b.ops[0], Op::AddCgroup { name } if name.as_ref() == "cg_1"));
assert!(matches!(&b.ops[1], Op::AddCgroup { name } if name.as_ref() == "cg_1/sub"));
}
#[test]
fn chain_with_op_interleaves_with_other_builders() {
let b = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_workers"))
.with_op(Op::add_cgroup("cg_empty"))
.with_payload(&TEST_PAYLOAD);
assert_eq!(b.cgroups.len(), 1);
assert_eq!(b.ops.len(), 1);
assert_eq!(b.payloads.len(), 1);
assert!(!b.is_empty());
}
}