use super::*;
use crate::peer::converge::{Entry, EntryKind};
fn entry(bytes: &[u8]) -> Entry {
Entry {
kind: EntryKind::File,
hash: crate::peer::converge::hash_bytes(bytes),
size: bytes.len() as u64,
executable: false,
}
}
#[test]
fn test9957_a_write_must_match_its_own_entry() {
let content = b"fn main() {}\n";
let honest = Write {
path: "src/main.rs".into(),
entry: entry(content),
content: crate::peer::identity::base64_encode(content),
};
assert_eq!(honest.decoded().expect("verified"), content);
let tampered = Write {
content: crate::peer::identity::base64_encode(b"fn main() { evil() }\n"),
..honest.clone()
};
let error = tampered.decoded().expect_err("a mismatched write must be refused");
assert!(error.contains("does not match the hash"), "{error}");
let wrong_size = Write {
entry: Entry {
size: 9999,
..entry(content)
},
..honest.clone()
};
let error = wrong_size.decoded().expect_err("a mismatched size must be refused");
assert!(error.contains("bytes"), "{error}");
let malformed = Write {
content: "!!!not base64!!!".into(),
..honest
};
assert!(malformed.decoded().is_err());
}
#[test]
fn test9958_the_baseline_digest_covers_everything_that_matters() {
let mut baseline = crate::peer::converge::Baseline::new();
baseline.insert("a.rs".into(), entry(b"a"));
baseline.insert("b.rs".into(), entry(b"b"));
let mut other = crate::peer::converge::Baseline::new();
other.insert("b.rs".into(), entry(b"b"));
other.insert("a.rs".into(), entry(b"a"));
assert_eq!(baseline_digest(&baseline), baseline_digest(&other));
for mutate in [
|b: &mut crate::peer::converge::Baseline| {
b.insert("a.rs".into(), entry(b"different"));
},
|b: &mut crate::peer::converge::Baseline| {
let mut e = entry(b"a");
e.executable = true;
b.insert("a.rs".into(), e);
},
|b: &mut crate::peer::converge::Baseline| {
let mut e = entry(b"a");
e.kind = EntryKind::Symlink;
b.insert("a.rs".into(), e);
},
|b: &mut crate::peer::converge::Baseline| {
b.remove("b.rs");
},
|b: &mut crate::peer::converge::Baseline| {
b.insert("c.rs".into(), entry(b"a"));
},
] {
let mut changed = baseline.clone();
mutate(&mut changed);
assert_ne!(
baseline_digest(&baseline),
baseline_digest(&changed),
"a baseline difference did not change the digest"
);
}
}
#[test]
fn test9959_every_message_survives_the_wire() {
let epoch = crate::peer::compatibility::Epoch {
repository: crate::peer::model::RepositoryId::root(),
root_commit: "abc".into(),
branch: Some("feature/peer".into()),
head: Some("def".into()),
git_state: crate::peer::compatibility::GitState::Settled,
};
let workspace = crate::peer::model::WorkspaceId::parse("ab12@main").expect("id");
let requests = vec![
Request::Inventory,
Request::Report {
workspace: workspace.clone(),
repositories: vec![crate::peer::model::RepositoryId::root()],
},
Request::Fetch {
workspace: workspace.clone(),
repository: crate::peer::model::RepositoryId::root(),
epoch: epoch.clone(),
paths: vec!["a.rs".into()],
},
Request::Apply {
workspace: workspace.clone(),
repository: crate::peer::model::RepositoryId::root(),
epoch: epoch.clone(),
writes: vec![Write {
path: "a.rs".into(),
entry: entry(b"a"),
content: crate::peer::identity::base64_encode(b"a"),
}],
deletions: vec!["gone.rs".into()],
found: [("gone.rs".to_string(), entry(b"old"))].into_iter().collect(),
baseline_digest: "digest".into(),
},
Request::Confirm {
workspace: workspace.clone(),
repository: crate::peer::model::RepositoryId::root(),
baseline_digest: "digest".into(),
},
Request::Acknowledge {
workspace,
repository: crate::peer::model::RepositoryId::root(),
epoch,
paths: vec!["a.rs".into()],
baseline_digest: "digest".into(),
},
];
for request in requests {
let text = serde_json::to_string(&request).expect("encode");
let back: Request = serde_json::from_str(&text).expect("decode");
assert_eq!(request, back);
}
let responses = vec![
Response::Inventory { workspaces: vec![] },
Response::Report {
workspace_present: Some(true),
repositories: vec![],
},
Response::Fetched { writes: vec![] },
Response::Applied {
applied: vec!["a.rs".into()],
},
Response::Acknowledged,
Response::Refused {
code: RefusalCode::EpochMoved,
detail: "the branch changed".into(),
},
];
for response in responses {
let text = serde_json::to_string(&response).expect("encode");
let back: Response = serde_json::from_str(&text).expect("decode");
assert_eq!(response, back);
}
let empty_write = Request::Apply {
workspace: crate::peer::model::WorkspaceId::parse("ab12@main").expect("id"),
repository: crate::peer::model::RepositoryId::root(),
epoch: crate::peer::compatibility::Epoch {
repository: crate::peer::model::RepositoryId::root(),
root_commit: "abc".into(),
branch: Some("main".into()),
head: Some("def".into()),
git_state: crate::peer::compatibility::GitState::Settled,
},
writes: vec![Write {
path: "empty".into(),
entry: entry(b""),
content: String::new(),
}],
deletions: vec![],
found: Default::default(),
baseline_digest: "d".into(),
};
let text = serde_json::to_string(&empty_write).expect("encode");
assert!(text.contains("\"deletions\":[]"), "{text}");
}