summaryrefslogtreecommitdiff
path: root/tests/compare.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/compare.rs')
-rw-r--r--tests/compare.rs306
1 files changed, 216 insertions, 90 deletions
diff --git a/tests/compare.rs b/tests/compare.rs
index ab63f9a..8ea9fdb 100644
--- a/tests/compare.rs
+++ b/tests/compare.rs
@@ -1,5 +1,5 @@
-use alt_controller_image::compare::{Change, SemanticDifference, compare};
use alt_controller_image::archive::NativeTarWriter;
+use alt_controller_image::compare::{Change, SemanticDifference, compare};
use alt_controller_image::manifest::{
ArchiveMemberRecord, ArtifactManifest, FileRecord, InitrdRecord, PackageRecord, ServiceRecord,
};
@@ -27,7 +27,10 @@ fn compares_added_removed_and_changed_semantic_records() {
PackageRecord::new("kernel-image-rt", "2.0"),
PackageRecord::new("controller-agent", "1.0"),
],
- vec![FileRecord::symlink("etc/controller.conf", "controller.conf.real")],
+ vec![FileRecord::symlink(
+ "etc/controller.conf",
+ "controller.conf.real",
+ )],
Some(InitrdRecord::new("boot/initrd-rt.img", "new-initrd")),
vec![ServiceRecord::new("controller.service", false)],
vec![ArchiveMemberRecord::new("usr/bin/controller", "file")],
@@ -39,13 +42,33 @@ fn compares_added_removed_and_changed_semantic_records() {
assert_eq!(
report.differences(),
&[
- SemanticDifference::Package { name: "controller-agent".into(), change: Change::Added },
- SemanticDifference::Package { name: "kernel-image-rt".into(), change: Change::Changed },
- SemanticDifference::File { path: "etc/controller.conf".into(), change: Change::Changed },
- SemanticDifference::Initrd { change: Change::Changed },
- SemanticDifference::Service { name: "controller.service".into(), change: Change::Changed },
- SemanticDifference::ArchiveMember { path: "etc/controller.conf".into(), change: Change::Removed },
- SemanticDifference::ArchiveMember { path: "usr/bin/controller".into(), change: Change::Added },
+ SemanticDifference::Package {
+ name: "controller-agent".into(),
+ change: Change::Added
+ },
+ SemanticDifference::Package {
+ name: "kernel-image-rt".into(),
+ change: Change::Changed
+ },
+ SemanticDifference::File {
+ path: "etc/controller.conf".into(),
+ change: Change::Changed
+ },
+ SemanticDifference::Initrd {
+ change: Change::Changed
+ },
+ SemanticDifference::Service {
+ name: "controller.service".into(),
+ change: Change::Changed
+ },
+ SemanticDifference::ArchiveMember {
+ path: "etc/controller.conf".into(),
+ change: Change::Removed
+ },
+ SemanticDifference::ArchiveMember {
+ path: "usr/bin/controller".into(),
+ change: Change::Added
+ },
]
);
assert!(report.render().contains("changed initrd"));
@@ -98,10 +121,12 @@ fn archive_collection_records_an_initrd_once_as_a_dedicated_boot_fact() {
"8f7ed204b9dfaa20aa484445f54233c4b407cb80ec0f8c07f1f0a59675fb44cf",
))
);
- assert!(manifest
- .files
- .iter()
- .all(|record| record.path != "boot/initrd-6.12-rt1.img"));
+ assert!(
+ manifest
+ .files
+ .iter()
+ .all(|record| record.path != "boot/initrd-6.12-rt1.img")
+ );
}
#[test]
@@ -123,10 +148,12 @@ fn rootfs_collection_records_a_supplied_initrd_once_as_a_dedicated_boot_fact() {
.expect("collect rootfs facts");
assert_eq!(manifest.initrd, Some(initrd));
- assert!(manifest
- .files
- .iter()
- .all(|record| record.path != "boot/initrd-6.12-rt1.img"));
+ assert!(
+ manifest
+ .files
+ .iter()
+ .all(|record| record.path != "boot/initrd-6.12-rt1.img")
+ );
}
#[test]
@@ -136,8 +163,14 @@ fn reads_and_writes_a_toml_manifest_beside_an_artifact() {
let manifest = baseline();
let manifest_path = manifest.write_beside(&artifact).expect("write manifest");
- assert_eq!(manifest_path, fixture.path().join("controller.tar.manifest.toml"));
- assert_eq!(ArtifactManifest::load(&manifest_path).expect("load manifest"), manifest);
+ assert_eq!(
+ manifest_path,
+ fixture.path().join("controller.tar.manifest.toml")
+ );
+ assert_eq!(
+ ArtifactManifest::load(&manifest_path).expect("load manifest"),
+ manifest
+ );
}
#[test]
@@ -146,16 +179,26 @@ fn writes_distinct_manifests_for_artifacts_in_the_same_directory() {
let legacy = fixture.path().join("legacy.tar");
let native = fixture.path().join("native.tar");
let legacy_manifest = baseline();
- let native_manifest = ArtifactManifest::new(vec![], vec![], None, vec![], vec![])
- .expect("valid native manifest");
+ let native_manifest =
+ ArtifactManifest::new(vec![], vec![], None, vec![], vec![]).expect("valid native manifest");
- let legacy_path = legacy_manifest.write_beside(&legacy).expect("write legacy manifest");
- let native_path = native_manifest.write_beside(&native).expect("write native manifest");
+ let legacy_path = legacy_manifest
+ .write_beside(&legacy)
+ .expect("write legacy manifest");
+ let native_path = native_manifest
+ .write_beside(&native)
+ .expect("write native manifest");
assert_eq!(legacy_path, fixture.path().join("legacy.tar.manifest.toml"));
assert_eq!(native_path, fixture.path().join("native.tar.manifest.toml"));
- assert_eq!(ArtifactManifest::load(&legacy_path).expect("load legacy manifest"), legacy_manifest);
- assert_eq!(ArtifactManifest::load(&native_path).expect("load native manifest"), native_manifest);
+ assert_eq!(
+ ArtifactManifest::load(&legacy_path).expect("load legacy manifest"),
+ legacy_manifest
+ );
+ assert_eq!(
+ ArtifactManifest::load(&native_path).expect("load native manifest"),
+ native_manifest
+ );
}
#[test]
@@ -170,13 +213,19 @@ fn refuses_to_overwrite_an_existing_companion_manifest() {
.expect_err("existing companion manifests must not be overwritten");
assert!(error.to_string().contains("create artifact manifest"));
- assert_eq!(fs::read_to_string(&manifest_path).expect("read existing manifest"), "preserve this manifest");
+ assert_eq!(
+ fs::read_to_string(&manifest_path).expect("read existing manifest"),
+ "preserve this manifest"
+ );
}
#[test]
fn rejects_duplicate_semantic_keys() {
let error = ArtifactManifest::new(
- vec![PackageRecord::new("controller", "1"), PackageRecord::new("controller", "2")],
+ vec![
+ PackageRecord::new("controller", "1"),
+ PackageRecord::new("controller", "2"),
+ ],
vec![],
None,
vec![],
@@ -202,7 +251,11 @@ fn rejects_malformed_file_records_before_comparison() {
vec![],
)
.expect_err("regular files require a digest");
- assert!(error.to_string().contains("regular file record requires a digest"));
+ assert!(
+ error
+ .to_string()
+ .contains("regular file record requires a digest")
+ );
let error = ArtifactManifest::new(
vec![],
@@ -217,7 +270,11 @@ fn rejects_malformed_file_records_before_comparison() {
vec![],
)
.expect_err("symlinks cannot carry a digest");
- assert!(error.to_string().contains("symlink record cannot carry a digest"));
+ assert!(
+ error
+ .to_string()
+ .contains("symlink record cannot carry a digest")
+ );
}
#[test]
@@ -231,7 +288,11 @@ fn rejects_malformed_initrd_records_before_comparison() {
)
.expect_err("initrd records require a digest");
- assert!(error.to_string().contains("initrd record requires a sha256 digest"));
+ assert!(
+ error
+ .to_string()
+ .contains("initrd record requires a sha256 digest")
+ );
}
#[test]
@@ -283,24 +344,37 @@ fn collects_semantic_facts_from_native_rootfs_and_tar_artifact() {
)
.expect("collect semantic facts");
- assert_eq!(manifest.packages, vec![PackageRecord::new("controller", "1.0")]);
- assert!(manifest.files.iter().any(|record| record == &FileRecord::file(
- "etc/controller.conf",
- "2d5c759b2b539229e09d362e8dbe0ae410ff8c9ece6038624458724520683f5b",
- )));
- assert!(manifest
- .files
- .iter()
- .any(|record| record == &FileRecord::symlink("etc/controller-link", "controller.conf")));
- assert_eq!(manifest.services, vec![ServiceRecord::new("controller.service", true)]);
- assert!(manifest
- .archive_members
- .iter()
- .any(|record| record == &ArchiveMemberRecord::new("etc/controller.conf", "file")));
- assert!(manifest
- .archive_members
- .iter()
- .any(|record| record == &ArchiveMemberRecord::new("etc/controller-link", "symlink")));
+ assert_eq!(
+ manifest.packages,
+ vec![PackageRecord::new("controller", "1.0")]
+ );
+ assert!(manifest.files.iter().any(|record| record
+ == &FileRecord::file(
+ "etc/controller.conf",
+ "2d5c759b2b539229e09d362e8dbe0ae410ff8c9ece6038624458724520683f5b",
+ )));
+ assert!(
+ manifest
+ .files
+ .iter()
+ .any(|record| record == &FileRecord::symlink("etc/controller-link", "controller.conf"))
+ );
+ assert_eq!(
+ manifest.services,
+ vec![ServiceRecord::new("controller.service", true)]
+ );
+ assert!(
+ manifest
+ .archive_members
+ .iter()
+ .any(|record| record == &ArchiveMemberRecord::new("etc/controller.conf", "file"))
+ );
+ assert!(
+ manifest
+ .archive_members
+ .iter()
+ .any(|record| record == &ArchiveMemberRecord::new("etc/controller-link", "symlink"))
+ );
}
#[test]
@@ -325,10 +399,11 @@ fn collects_comparable_semantic_facts_directly_from_a_tar_artifact() {
let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
assert_eq!(manifest.packages, Vec::<PackageRecord>::new());
- assert!(manifest.files.iter().any(|record| record == &FileRecord::file(
- "etc/controller.conf",
- "2d5c759b2b539229e09d362e8dbe0ae410ff8c9ece6038624458724520683f5b",
- )));
+ assert!(manifest.files.iter().any(|record| record
+ == &FileRecord::file(
+ "etc/controller.conf",
+ "2d5c759b2b539229e09d362e8dbe0ae410ff8c9ece6038624458724520683f5b",
+ )));
assert_eq!(
manifest.initrd,
Some(InitrdRecord::new(
@@ -336,7 +411,10 @@ fn collects_comparable_semantic_facts_directly_from_a_tar_artifact() {
"8f7ed204b9dfaa20aa484445f54233c4b407cb80ec0f8c07f1f0a59675fb44cf",
))
);
- assert_eq!(manifest.services, vec![ServiceRecord::new("controller.service", true)]);
+ assert_eq!(
+ manifest.services,
+ vec![ServiceRecord::new("controller.service", true)]
+ );
}
#[test]
@@ -350,11 +428,16 @@ fn normalizes_legacy_dot_prefixed_archive_paths_before_comparison() {
header.set_mode(0o644);
header.set_cksum();
archive
- .append_data(&mut header, "./etc/controller.conf", Cursor::new(b"controller\n"))
+ .append_data(
+ &mut header,
+ "./etc/controller.conf",
+ Cursor::new(b"controller\n"),
+ )
.expect("append legacy-style member");
archive.finish().expect("finish legacy archive");
- let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect legacy archive facts");
+ let manifest =
+ ArtifactManifest::collect_archive(&artifact).expect("collect legacy archive facts");
let expected = ArtifactManifest::new(
vec![],
vec![FileRecord::file(
@@ -391,7 +474,11 @@ fn rejects_duplicate_archive_member_paths_before_semantic_comparison() {
let error = ArtifactManifest::collect_archive(&artifact)
.expect_err("ambiguous archive paths cannot be compared semantically");
- assert!(error.to_string().contains("duplicate archive member record: etc/controller.conf"));
+ assert!(
+ error
+ .to_string()
+ .contains("duplicate archive member record: etc/controller.conf")
+ );
}
#[test]
@@ -405,7 +492,11 @@ fn collects_hardlink_targets_from_an_archive_for_semantic_comparison() {
header.set_mode(0o644);
header.set_cksum();
archive
- .append_data(&mut header, "./usr/bin/controller", Cursor::new(b"controller\n"))
+ .append_data(
+ &mut header,
+ "./usr/bin/controller",
+ Cursor::new(b"controller\n"),
+ )
.expect("append regular member");
let mut link_header = tar::Header::new_gnu();
link_header.set_entry_type(tar::EntryType::Link);
@@ -447,9 +538,10 @@ fn rootfs_collection_preserves_hardlink_facts_like_archive_collection() {
.write(&rootfs, &artifact)
.expect("write native archive");
- let rootfs_manifest = ArtifactManifest::collect(&rootfs, vec![], None, &artifact)
- .expect("collect rootfs facts");
- let archive_manifest = ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
+ let rootfs_manifest =
+ ArtifactManifest::collect(&rootfs, vec![], None, &artifact).expect("collect rootfs facts");
+ let archive_manifest =
+ ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
assert_eq!(rootfs_manifest.files, archive_manifest.files);
assert!(rootfs_manifest.files.iter().any(|record| {
@@ -464,17 +556,28 @@ fn normalizes_dot_prefixed_paths_from_a_legacy_tree_archive() {
fs::create_dir_all(rootfs.join("etc")).expect("create rootfs directory");
fs::write(rootfs.join("etc/controller.conf"), "controller\n").expect("write rootfs file");
let artifact = fixture.path().join("legacy.tar");
- let mut archive = tar::Builder::new(fs::File::create(&artifact).expect("create legacy archive"));
- archive.append_dir_all(".", &rootfs).expect("write legacy tree archive");
+ let mut archive =
+ tar::Builder::new(fs::File::create(&artifact).expect("create legacy archive"));
+ archive
+ .append_dir_all(".", &rootfs)
+ .expect("write legacy tree archive");
archive.finish().expect("finish legacy archive");
- let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect legacy archive facts");
+ let manifest =
+ ArtifactManifest::collect_archive(&artifact).expect("collect legacy archive facts");
- assert!(manifest.files.iter().all(|record| !record.path.starts_with("./")));
- assert!(manifest
- .archive_members
- .iter()
- .all(|record| !record.path.starts_with("./")));
+ assert!(
+ manifest
+ .files
+ .iter()
+ .all(|record| !record.path.starts_with("./"))
+ );
+ assert!(
+ manifest
+ .archive_members
+ .iter()
+ .all(|record| !record.path.starts_with("./"))
+ );
}
#[test]
@@ -489,20 +592,26 @@ fn excludes_legacy_internal_host_and_fakedata_archive_members() {
fs::write(rootfs.join("etc/controller.conf"), "controller\n").expect("write visible file");
let legacy = fixture.path().join("legacy.tar");
let native = fixture.path().join("native.tar");
- let mut legacy_writer = tar::Builder::new(fs::File::create(&legacy).expect("create legacy archive"));
+ let mut legacy_writer =
+ tar::Builder::new(fs::File::create(&legacy).expect("create legacy archive"));
legacy_writer
.append_dir_all(".", &rootfs)
.expect("write legacy archive with internal metadata");
legacy_writer.finish().expect("finish legacy archive");
- NativeTarWriter::new().write(&rootfs, &native).expect("write native archive");
+ NativeTarWriter::new()
+ .write(&rootfs, &native)
+ .expect("write native archive");
let legacy_manifest = ArtifactManifest::collect_archive(&legacy).expect("collect legacy facts");
let native_manifest = ArtifactManifest::collect_archive(&native).expect("collect native facts");
- assert!(legacy_manifest
- .archive_members
- .iter()
- .all(|record| !record.path.starts_with(".host/") && !record.path.starts_with(".fakedata/")));
+ assert!(
+ legacy_manifest
+ .archive_members
+ .iter()
+ .all(|record| !record.path.starts_with(".host/")
+ && !record.path.starts_with(".fakedata/"))
+ );
let report = compare(&legacy_manifest, &native_manifest);
assert!(report.is_equivalent(), "{}", report.render());
}
@@ -519,16 +628,21 @@ fn native_manifest_collection_excludes_internal_members_from_its_archive_facts()
fs::write(rootfs.join("etc/controller.conf"), "controller\n").expect("write visible file");
let artifact = fixture.path().join("legacy.tar");
let mut writer = tar::Builder::new(fs::File::create(&artifact).expect("create legacy archive"));
- writer.append_dir_all(".", &rootfs).expect("write legacy archive");
+ writer
+ .append_dir_all(".", &rootfs)
+ .expect("write legacy archive");
writer.finish().expect("finish legacy archive");
let manifest = ArtifactManifest::collect(&rootfs, vec![], None, &artifact)
.expect("collect native filesystem and archive facts");
- assert!(manifest
- .archive_members
- .iter()
- .all(|record| !record.path.starts_with(".host/") && !record.path.starts_with(".fakedata/")));
+ assert!(
+ manifest
+ .archive_members
+ .iter()
+ .all(|record| !record.path.starts_with(".host/")
+ && !record.path.starts_with(".fakedata/"))
+ );
}
#[test]
@@ -541,19 +655,25 @@ fn archive_collection_excludes_nested_internal_metadata_members() {
fs::write(rootfs.join("etc/controller.conf"), "controller\n").expect("write visible file");
let artifact = fixture.path().join("legacy.tar");
let mut writer = tar::Builder::new(fs::File::create(&artifact).expect("create legacy archive"));
- writer.append_dir_all(".", &rootfs).expect("write legacy archive");
+ writer
+ .append_dir_all(".", &rootfs)
+ .expect("write legacy archive");
writer.finish().expect("finish legacy archive");
let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
- assert!(manifest
- .archive_members
- .iter()
- .all(|record| !record.path.split('/').any(|component| component == ".fakedata")));
- assert!(manifest
- .files
- .iter()
- .all(|record| !record.path.split('/').any(|component| component == ".fakedata")));
+ assert!(manifest.archive_members.iter().all(|record| {
+ !record
+ .path
+ .split('/')
+ .any(|component| component == ".fakedata")
+ }));
+ assert!(manifest.files.iter().all(|record| {
+ !record
+ .path
+ .split('/')
+ .any(|component| component == ".fakedata")
+ }));
}
#[test]
@@ -575,7 +695,10 @@ fn rootfs_collection_recognizes_services_enabled_by_non_default_targets() {
let manifest = ArtifactManifest::collect(&rootfs, vec![], None, &artifact)
.expect("collect native filesystem and archive facts");
- assert_eq!(manifest.services, vec![ServiceRecord::new("controller.service", true)]);
+ assert_eq!(
+ manifest.services,
+ vec![ServiceRecord::new("controller.service", true)]
+ );
}
#[test]
@@ -598,7 +721,10 @@ fn archive_collection_coalesces_a_service_enabled_by_multiple_targets() {
let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
- assert_eq!(manifest.services, vec![ServiceRecord::new("controller.service", true)]);
+ assert_eq!(
+ manifest.services,
+ vec![ServiceRecord::new("controller.service", true)]
+ );
}
#[test]