use super::build_distribution::*;
#[test]
fn build_far_empty_dir() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
std::fs::create_dir_all(&oci).unwrap();
let result = cmd_build_far("test-image", &oci);
assert!(result.is_ok());
let far_path = oci.with_extension("far");
assert!(far_path.exists());
}
#[test]
fn build_far_with_files() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
std::fs::create_dir_all(&oci).unwrap();
std::fs::write(oci.join("manifest.json"), r#"{"schemaVersion":2}"#).unwrap();
std::fs::write(oci.join("index.json"), r#"{"mediaType":"application/vnd.oci.image.index.v1+json"}"#).unwrap();
let result = cmd_build_far("my-app", &oci);
assert!(result.is_ok());
let far_path = oci.with_extension("far");
assert!(far_path.exists());
assert!(far_path.metadata().unwrap().len() > 0);
}
#[test]
fn build_far_nested_dirs() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
std::fs::create_dir_all(oci.join("blobs/sha256")).unwrap();
std::fs::write(oci.join("blobs/sha256/abc123"), "layer data").unwrap();
std::fs::write(oci.join("oci-layout"), r#"{"imageLayoutVersion":"1.0.0"}"#).unwrap();
let result = cmd_build_far("nested-test", &oci);
assert!(result.is_ok());
}
const DEAD_REGISTRY: &str = "127.0.0.1:1";
fn write_oci_layout(oci: &std::path::Path) {
let blobs = oci.join("blobs").join("sha256");
std::fs::create_dir_all(&blobs).unwrap();
let layer_hex = "1".repeat(64);
let config_hex = "2".repeat(64);
let manifest_hex = "3".repeat(64);
std::fs::write(blobs.join(&layer_hex), b"layer-bytes").unwrap();
let config = br#"{"architecture":"amd64","os":"linux"}"#;
std::fs::write(blobs.join(&config_hex), config).unwrap();
let manifest = format!(
r#"{{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json",
"config":{{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:{config_hex}","size":{}}},
"layers":[{{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:{layer_hex}","size":11}}]}}"#,
config.len()
);
std::fs::write(blobs.join(&manifest_hex), manifest.as_bytes()).unwrap();
let index = format!(
r#"{{"schemaVersion":2,"manifests":[{{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:{manifest_hex}","size":{}}}]}}"#,
manifest.len()
);
std::fs::write(oci.join("index.json"), index.as_bytes()).unwrap();
}
#[test]
fn push_to_an_unreachable_registry_is_an_error_not_a_skip() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
write_oci_layout(&oci);
let err = cmd_build_push(&format!("{DEAD_REGISTRY}/team/app:v1"), &oci)
.expect_err("a push that reached no registry must not report success");
assert!(
!err.to_lowercase().contains("skip"),
"an unreachable registry is a failed push, not a skipped one: {err}"
);
assert!(
err.contains(DEAD_REGISTRY),
"the error must name the registry it could not push to: {err}"
);
}
#[test]
fn push_refuses_an_empty_oci_layout() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
std::fs::create_dir_all(&oci).unwrap();
let err = cmd_build_push(&format!("{DEAD_REGISTRY}/team/app:v1"), &oci)
.expect_err("pushing an empty layout must not report success");
assert!(err.contains("nothing to push"), "{err}");
}
#[test]
fn push_refuses_a_layout_with_no_manifest() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
let blobs = oci.join("blobs").join("sha256");
std::fs::create_dir_all(&blobs).unwrap();
std::fs::write(blobs.join("4".repeat(64)), b"orphan").unwrap();
std::fs::write(oci.join("index.json"), br#"{"schemaVersion":2,"manifests":[]}"#).unwrap();
let err = cmd_build_push(&format!("{DEAD_REGISTRY}/team/app:v1"), &oci)
.expect_err("a layout with no manifest must not report a completed push");
assert!(err.contains("no manifest"), "{err}");
}
#[test]
fn push_rejects_a_reference_it_cannot_target() {
let dir = tempfile::tempdir().unwrap();
let oci = dir.path().join("oci");
write_oci_layout(&oci);
for reference in ["", "ghcr.io/foo/bar@sha256:abc", "ghcr.io/Foo/Bar:1"] {
assert!(
cmd_build_push(reference, &oci).is_err(),
"reference {reference:?} must be refused, not silently replaced by a default"
);
}
}