use std::fs;
use crate::deploy::test_support::{
Fixture, RECLAIMED, Shepherd, fixture_before_any_release, install_release,
};
use crate::deploy::{Outcome, deploy, unattended};
use crate::paths::Tree;
use crate::state::State;
use crate::{fixtures, git, swap};
const RELOAD: &str = "reload = ['cmd/voting']\n";
fn declaring_reload_paths() -> Shepherd {
Shepherd::ready().with_settings(RELOAD)
}
fn fixture_declaring_reload_paths() -> Fixture {
let mut fixture = fixture_before_any_release();
fixtures::commit(
fixture.origin.path(),
&[("cmd/voting/main.go", "1"), ("cmd/bot/main.go", "1")],
"add the paths",
);
git::fetch(
&fixture.tree.git(),
&fixture.state.remote,
"main",
fixtures::TEST_BUDGET,
)
.expect("fetch");
let live = git::remote_head(&fixture.tree.git(), "main").expect("head");
install_release(&fixture, &live);
fixture.state.deployed = Some(live);
fixture
.state
.write(&fixture.tree.state_file())
.expect("write deploy.toml");
fixture
}
fn push(fixture: &Fixture, files: &[(&str, &str)]) -> String {
fixtures::commit(fixture.origin.path(), files, "push");
fixtures::head_of(fixture.origin.path())
}
#[tokio::test(start_paused = true)]
async fn an_unattended_deploy_skips_a_push_outside_the_paths() {
let mut fixture = fixture_declaring_reload_paths();
let live = swap::resolve(&fixture.tree.current()).expect("resolves");
let before = State::read(&fixture.tree.state_file()).expect("reads");
let pushed = push(&fixture, &[("cmd/bot/main.go", "2")]);
let shepherd = declaring_reload_paths();
let outcome = unattended(
&shepherd,
&fixture.tree,
&mut fixture.state,
&fixtures::dog_config(),
)
.await
.expect("completes");
assert_eq!(
outcome,
Outcome::Skipped {
sha: pushed.clone()
}
);
assert_eq!(shepherd.reload_count(), 0);
assert_eq!(swap::resolve(&fixture.tree.current()).unwrap(), live);
assert!(!fixture.tree.release(&pushed).exists(), "no checkout");
assert_eq!(
State::read(&fixture.tree.state_file()).expect("reads"),
before,
"the record is untouched"
);
assert_eq!(fixture.state, before, "and so is the copy in memory");
}
#[tokio::test(start_paused = true)]
async fn a_deploy_by_name_does_not_skip() {
let mut fixture = fixture_declaring_reload_paths();
let pushed = push(&fixture, &[("cmd/bot/main.go", "2")]);
let outcome = deploy(
&declaring_reload_paths(),
&fixture.tree,
&mut fixture.state,
&fixtures::dog_config(),
)
.await
.expect("completes");
assert_eq!(outcome, Outcome::Deployed { sha: pushed });
}
#[tokio::test(start_paused = true)]
async fn a_skipped_push_counts_toward_the_next_real_one() {
let mut fixture = fixture_declaring_reload_paths();
let config = fixtures::dog_config();
let skipped = push(&fixture, &[("cmd/bot/main.go", "2")]);
let first = unattended(
&declaring_reload_paths(),
&fixture.tree,
&mut fixture.state,
&config,
)
.await
.expect("completes");
assert_eq!(
first,
Outcome::Skipped {
sha: skipped.clone()
}
);
let real = push(&fixture, &[("cmd/voting/main.go", "2")]);
let second = unattended(
&declaring_reload_paths(),
&fixture.tree,
&mut fixture.state,
&config,
)
.await
.expect("completes");
assert_eq!(second, Outcome::Deployed { sha: real.clone() });
let release = fixture.tree.release(&real);
assert_eq!(
fs::read_to_string(release.join("cmd/bot/main.go")).expect("reads"),
"2",
"the skipped push's change is in the release"
);
}
#[tokio::test(start_paused = true)]
async fn a_failure_to_decide_deploys_as_before() {
let mut fixture = fixture_declaring_reload_paths();
let pushed = push(&fixture, &[("cmd/bot/main.go", "2")]);
fixture.state.deployed = Some(RECLAIMED.to_owned());
let outcome = unattended(
&declaring_reload_paths(),
&fixture.tree,
&mut fixture.state,
&fixtures::dog_config(),
)
.await
.expect("completes");
assert_eq!(outcome, Outcome::Deployed { sha: pushed });
let mut fixture = fixture_declaring_reload_paths();
let pushed = push(&fixture, &[("cmd/bot/main.go", "2")]);
let outcome = unattended(
&Shepherd::ready().with_settings("reload = [':(bogus)cmd']\n"),
&fixture.tree,
&mut fixture.state,
&fixtures::dog_config(),
)
.await
.expect("completes");
assert_eq!(outcome, Outcome::Deployed { sha: pushed });
}
fn another_sheep(fixture: &Fixture, name: &str) -> (Tree, State) {
let tree = Tree::for_sheep(fixture.home.path(), name);
std::fs::create_dir_all(tree.git()).expect("create git dir");
fixtures::run_git(&tree.git(), &["init", "-q", "--bare"]);
git::fetch(
&tree.git(),
&fixture.state.remote,
"main",
fixtures::TEST_BUDGET,
)
.expect("fetch");
fixture
.state
.write(&tree.state_file())
.expect("deploy.toml");
(tree, fixture.state.clone())
}
#[tokio::test(start_paused = true)]
async fn two_sheep_with_different_reload_lists_deploy_only_the_one_the_push_touches() {
let mut voting = fixture_declaring_reload_paths();
let (bot_tree, mut bot_state) = another_sheep(&voting, "bot");
let pushed = push(&voting, &[("cmd/voting/main.go", "2")]);
let voting_daemon = Shepherd::ready().with_settings("reload = ['cmd/voting']\n");
let bot_daemon = Shepherd::ready().with_settings("reload = ['cmd/bot']\n");
let voting_outcome = unattended(
&voting_daemon,
&voting.tree,
&mut voting.state,
&fixtures::dog_config(),
)
.await
.expect("completes");
let bot_outcome = unattended(
&bot_daemon,
&bot_tree,
&mut bot_state,
&fixtures::dog_config(),
)
.await
.expect("completes");
assert_eq!(
voting_outcome,
Outcome::Deployed {
sha: pushed.clone()
}
);
assert_eq!(bot_outcome, Outcome::Skipped { sha: pushed });
assert_eq!(voting_daemon.reload_count(), 1);
assert_eq!(bot_daemon.reload_count(), 0);
}