use std::fs;
mod common;
use common::Environment;
#[test]
fn create_environment() -> anyhow::Result<()> {
let e = Environment::new()?;
assert!(e.gnupg_state().exists());
assert!(e.git_state().exists());
Ok(())
}
#[test]
fn make_commit() -> anyhow::Result<()> {
let e = Environment::new()?;
let p = e.git_state();
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Initial commit.",
])?;
Ok(())
}
#[test]
fn sign_commit() -> anyhow::Result<()> {
let e = Environment::new()?;
let p = e.git_state();
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Initial commit.",
&format!("-S{}", e.willow.fingerprint),
])?;
Ok(())
}
#[test]
fn verify_commit() -> anyhow::Result<()> {
let e = Environment::new()?;
let p = e.git_state();
e.sq_git(&[
"policy",
"authorize",
e.willow.petname,
&e.willow.fingerprint.to_string(),
"--sign-commit"
])?;
e.git(&["add", "openpgp-policy.toml"])?;
e.git(&[
"commit",
"-m", "Initial commit.",
&format!("-S{}", e.willow.fingerprint),
])?;
let root = e.git_current_commit()?;
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "First change.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.sq_git(&["log", "--trust-root", &root])?;
fs::write(p.join("a"), "Und es bleibt schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Second change.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.sq_git(&["log", "--trust-root", &root])?;
Ok(())
}
#[test]
fn shadow_verify_commit() -> anyhow::Result<()> {
let e = Environment::new()?;
let p = e.git_state();
e.sq_git(&[
"policy",
"authorize",
"--policy-file", "shadow-policy.toml",
e.willow.petname,
&e.willow.fingerprint.to_string(),
"--sign-commit"
])?;
fs::write(p.join("a"), "Aller Anfang ist schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Initial commit.",
&format!("-S{}", e.willow.fingerprint),
])?;
let root = e.git_current_commit()?;
e.sq_git(&[
"log",
"--trust-root", &root,
"--policy-file", "shadow-policy.toml",
])?;
fs::write(p.join("a"), "Und es bleibt schwer.")?;
e.git(&["add", "a"])?;
e.git(&[
"commit",
"-m", "Second change.",
&format!("-S{}", e.willow.fingerprint),
])?;
e.sq_git(&[
"log",
"--trust-root", &root,
"--policy-file", "shadow-policy.toml",
])?;
Ok(())
}
#[test]
fn commit_with_no_policy() -> anyhow::Result<()>
{
let (e, root) = Environment::scooby_gang_bootstrap(None)?;
e.git(&["checkout", "-b", "main"])
.expect("can create branch");
e.git_commit(
&[("pre-fork", Some(b"xxx"))],
"pre-fork commit (willow)",
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
e.git(&["checkout", "-b", "no-policy"])
.expect("can create no-policy branch");
e.git(&["rm", "openpgp-policy.toml"])
.expect("can remove openpgp-policy.toml");
e.git_commit(
&[("no-policy", Some(b"xxx"))],
"no-policy commit",
None).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_err());
e.git(&["switch", "main"]).expect("can switch to main");
for i in 0..3 {
e.git_commit(
&[(&format!("main-{}", i), Some(b"xxx"))],
&format!("main commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
}
e.git_merge_no_ff(&[&"no-policy", "main"],
"Merge (willow)",
Some(&e.willow_release),
&[]).unwrap();
eprintln!("Graph:\n{}", e.git_log_graph().unwrap());
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)]).is_ok());
Ok(())
}
fn merge(pre_fork_commits: usize, feature_commits: (bool, usize), main_commits: usize)
-> anyhow::Result<()>
{
eprintln!("========================================================");
eprintln!("Testing configuration: {} pre-fork commits, \
{} {} authorized feature commits, {} main commits",
pre_fork_commits,
feature_commits.1,
if feature_commits.0 {
""
} else {
"not "
},
main_commits);
let (e, root) = Environment::scooby_gang_bootstrap(None)?;
e.git(&["checkout", "-b", "main"])
.expect("can create branch");
for i in 0..pre_fork_commits {
e.git_commit(
&[(&format!("pre-fork-{}", i), Some(b"xxx"))],
&format!("pre-fork commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
}
e.git(&["checkout", "-b", "feature"])
.expect("can create feature branch");
let mut feature_head = "feature".to_string();
let feature_commits_authorized = feature_commits.0;
let feature_commit_signer = if feature_commits_authorized {
&e.willow_release
} else {
&e.xander
};
for i in 0..feature_commits.1 {
feature_head
= e.git_commit(
&[(&format!("feature-{}", i), Some(b"xxx"))],
&format!("feature commit #{} ({})",
i + 1, feature_commit_signer.petname),
Some(&feature_commit_signer)).unwrap();
assert_eq!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok(),
feature_commits_authorized);
}
e.git(&["switch", "main"]).expect("can switch to main");
for i in 0..main_commits {
e.git_commit(
&[(&format!("main-{}", i), Some(b"xxx"))],
&format!("main commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
if i == 0 {
e.git(&["checkout", "-b", "main-continued"])
.expect("can create feature branch");
}
}
e.git_merge_no_ff(&[&feature_head, "main"],
"Merge (willow)",
Some(&e.willow_release),
&[]).unwrap();
eprintln!("Graph:\n{}", e.git_log_graph().unwrap());
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)]).is_ok());
for i in 0..2 {
e.git_commit(
&[(&format!("post-merge-{}", i), Some(b"xxx"))],
&format!("post-merge commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
}
if main_commits > 0 {
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("main-continued..")])
.is_ok());
}
assert_eq!(e.sq_git(&["log", "--trust-root", &root,
&format!("feature..")])
.is_ok(),
feature_commits_authorized);
Ok(())
}
fn merge_cross_product(pre_fork: &[usize],
feature: &[(bool, usize)],
main: &[usize])
{
for (&pre_fork_commits, &feature_commits, &main_commits) in
pre_fork.into_iter().flat_map(|pre| {
feature.into_iter().flat_map(move |feature| {
main.into_iter().map(move |main| {
(pre, feature, main)
})
})
})
{
merge(pre_fork_commits, feature_commits, main_commits)
.expect(&format!("Test pre-fork commits: {}, \
feature commits: {:?}, \
main commits: {} \
failed",
pre_fork_commits,
feature_commits,
main_commits));
}
}
#[test] fn merge_0_1_unauthorized_0() { merge_cross_product(&[0], &[(false, 1)], &[0]) }
#[test] fn merge_0_1_unauthorized_1() { merge_cross_product(&[0], &[(false, 1)], &[1]) }
#[test] fn merge_0_1_unauthorized_4() { merge_cross_product(&[0], &[(false, 1)], &[4]) }
#[test] fn merge_0_4_unauthorized_0() { merge_cross_product(&[0], &[(false, 4)], &[0]) }
#[test] fn merge_0_4_unauthorized_1() { merge_cross_product(&[0], &[(false, 4)], &[1]) }
#[test] fn merge_0_4_unauthorized_4() { merge_cross_product(&[0], &[(false, 4)], &[4]) }
#[test] fn merge_1_1_unauthorized_0() { merge_cross_product(&[1], &[(false, 1)], &[0]) }
#[test] fn merge_1_1_unauthorized_1() { merge_cross_product(&[1], &[(false, 1)], &[1]) }
#[test] fn merge_1_1_unauthorized_4() { merge_cross_product(&[1], &[(false, 1)], &[4]) }
#[test] fn merge_1_4_unauthorized_0() { merge_cross_product(&[1], &[(false, 4)], &[0]) }
#[test] fn merge_1_4_unauthorized_1() { merge_cross_product(&[1], &[(false, 4)], &[1]) }
#[test] fn merge_1_4_unauthorized_4() { merge_cross_product(&[1], &[(false, 4)], &[4]) }
#[test] fn merge_2_1_unauthorized_0() { merge_cross_product(&[2], &[(false, 1)], &[0]) }
#[test] fn merge_2_1_unauthorized_1() { merge_cross_product(&[2], &[(false, 1)], &[1]) }
#[test] fn merge_2_1_unauthorized_4() { merge_cross_product(&[2], &[(false, 1)], &[4]) }
#[test] fn merge_2_4_unauthorized_0() { merge_cross_product(&[2], &[(false, 4)], &[0]) }
#[test] fn merge_2_4_unauthorized_1() { merge_cross_product(&[2], &[(false, 4)], &[1]) }
#[test] fn merge_2_4_unauthorized_4() { merge_cross_product(&[2], &[(false, 4)], &[4]) }
#[test] fn merge_0_1_authorized_0() { merge_cross_product(&[0], &[(true, 1)], &[0]) }
#[test] fn merge_0_1_authorized_1() { merge_cross_product(&[0], &[(true, 1)], &[1]) }
#[test] fn merge_0_1_authorized_4() { merge_cross_product(&[0], &[(true, 1)], &[4]) }
#[test] fn merge_0_4_authorized_0() { merge_cross_product(&[0], &[(true, 4)], &[0]) }
#[test] fn merge_0_4_authorized_1() { merge_cross_product(&[0], &[(true, 4)], &[1]) }
#[test] fn merge_0_4_authorized_4() { merge_cross_product(&[0], &[(true, 4)], &[4]) }
#[test] fn merge_1_1_authorized_0() { merge_cross_product(&[1], &[(true, 1)], &[0]) }
#[test] fn merge_1_1_authorized_1() { merge_cross_product(&[1], &[(true, 1)], &[1]) }
#[test] fn merge_1_1_authorized_4() { merge_cross_product(&[1], &[(true, 1)], &[4]) }
#[test] fn merge_1_4_authorized_0() { merge_cross_product(&[1], &[(true, 4)], &[0]) }
#[test] fn merge_1_4_authorized_1() { merge_cross_product(&[1], &[(true, 4)], &[1]) }
#[test] fn merge_1_4_authorized_4() { merge_cross_product(&[1], &[(true, 4)], &[4]) }
#[test] fn merge_2_1_authorized_0() { merge_cross_product(&[2], &[(true, 1)], &[0]) }
#[test] fn merge_2_1_authorized_1() { merge_cross_product(&[2], &[(true, 1)], &[1]) }
#[test] fn merge_2_1_authorized_4() { merge_cross_product(&[2], &[(true, 1)], &[4]) }
#[test] fn merge_2_4_authorized_0() { merge_cross_product(&[2], &[(true, 4)], &[0]) }
#[test] fn merge_2_4_authorized_1() { merge_cross_product(&[2], &[(true, 4)], &[1]) }
#[test] fn merge_2_4_authorized_4() { merge_cross_product(&[2], &[(true, 4)], &[4]) }
#[test]
fn via_commit() -> anyhow::Result<()>
{
let (e, root) = Environment::scooby_gang_bootstrap(None)?;
e.git(&["checkout", "-b", "main"])
.expect("can create branch");
let mut pre_fork_commits = Vec::new();
for i in 0..3 {
let commit = e.git_commit(
&[(&format!("pre-fork-{}", i), Some(b"xxx"))],
&format!("pre-fork commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
pre_fork_commits.push(commit);
}
e.git(&["switch", "main"]).expect("can switch to main");
e.git(&["checkout", "-b", "good-a"])
.expect("can create good-a branch");
let mut good_a = Vec::new();
for i in 0..5 {
let commit = e.git_commit(
&[(&format!("good-a-{}", i), Some(b"xxx"))],
&format!("good-a commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
good_a.push(commit);
}
e.git(&["switch", "main"]).expect("can switch to main");
e.git(&["checkout", "-b", "good-b"])
.expect("can create good-b branch");
let mut good_b = Vec::new();
for i in 0..5 {
let commit = e.git_commit(
&[(&format!("good-b-{}", i), Some(b"xxx"))],
&format!("good-b commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
if i == 3 {
e.git_merge_no_ff(
&[
&good_a[0],
&commit,
],
"b merge: good a #1, good b #4 merge (willow)",
Some(&e.willow_release),
&[]).unwrap();
}
good_b.push(commit);
}
e.git(&["switch", "main"]).expect("can switch to main");
e.git(&["checkout", "-b", "bad"])
.expect("can create bad branch");
let mut bad = Vec::new();
for i in 0..5 {
let commit = e.git_commit(
&[(&format!("bad-{}", i), Some(b"xxx"))],
&format!("feature commit #{} (xander)", i + 1),
Some(&e.xander)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_err());
if i == 2 {
e.git_merge_no_ff(
&[
&good_a[2],
&good_b[2],
&commit,
],
"bad merge: good a #3, good b #3, bad #3 merge (willow)",
Some(&e.willow_release),
&[]).unwrap();
}
bad.push(commit);
}
e.git_merge_no_ff(
&[
&good_a.last().expect("have one"),
&good_b.last().expect("have one"),
&bad.last().expect("have one"),
],
"Merge (willow)",
Some(&e.willow_release),
&[]).unwrap();
eprintln!("Graph:\n{}", e.git_log_graph().unwrap());
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)]).is_ok());
let mut post_merge = Vec::new();
for i in 0..2 {
let commit = e.git_commit(
&[(&format!("post-merge-{}", i), Some(b"xxx"))],
&format!("post-merge commit #{} (willow)", i + 1),
Some(&e.willow_release)).unwrap();
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", root)])
.is_ok());
post_merge.push(commit);
}
for (i, commit) in pre_fork_commits.iter().enumerate() {
eprintln!("Checking via pre-fork-{}", i + 1);
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", commit)])
.is_ok());
}
for (i, commit) in good_a.iter().enumerate() {
eprintln!("Checking via good-a-{}", i + 1);
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", commit)])
.is_ok());
}
for (i, commit) in good_b.iter().enumerate() {
eprintln!("Checking via good-b-{}", i + 1);
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", commit)])
.is_ok());
}
for (i, commit) in bad.iter().enumerate() {
eprintln!("Checking via bad-{}", i + 1);
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", commit)])
.is_err());
}
for (i, commit) in post_merge.iter().enumerate() {
eprintln!("Checking via post-merge-{}", i + 1);
assert!(e.sq_git(&["log", "--trust-root", &root,
&format!("{}..", commit)])
.is_ok());
}
Ok(())
}