hf2q 0.1.10

Pure Rust CLI for converting HuggingFace models to hardware-optimized formats and serving them over an OpenAI-compatible API on Apple Silicon
use super::*;

use crate::convert::receipt::{
    ConversionReceipt, ConverterReceipt, ExcludedDsparkReceipt, OutputReceipt,
    PeakChunkBoundReceipt, SourceReceipt, CONVERSION_RECEIPT_SCHEMA_VERSION,
};
use crate::core::sha256::compute_file_sha256;
use crate::serve::cache::{CacheManifest, ModelEntry, QuantEntry};
use std::collections::BTreeMap;
use std::io::Write;

fn write_q4_k_m_gguf(path: &Path) {
    let key = b"general.file_type";
    let mut gguf = Vec::new();
    gguf.extend_from_slice(b"GGUF");
    gguf.extend_from_slice(&3_u32.to_le_bytes());
    gguf.extend_from_slice(&0_u64.to_le_bytes());
    gguf.extend_from_slice(&1_u64.to_le_bytes());
    gguf.extend_from_slice(&(key.len() as u64).to_le_bytes());
    gguf.extend_from_slice(key);
    gguf.extend_from_slice(&4_u32.to_le_bytes());
    gguf.extend_from_slice(&15_u32.to_le_bytes());
    gguf.resize(256, 0);
    fs::write(path, gguf).unwrap();
}

fn receipt_for(artifact: &Path, repository: &str) -> ConversionReceipt {
    ConversionReceipt {
        schema_version: CONVERSION_RECEIPT_SCHEMA_VERSION,
        source: SourceReceipt {
            original_reference: repository.into(),
            repository_id: repository.into(),
            repository_type: "model".into(),
            canonical_url: format!("https://huggingface.co/{repository}"),
            revision: "a".repeat(40),
            filename: None,
            bundle_sha256: "b".repeat(64),
            files: Vec::new(),
        },
        converter: ConverterReceipt {
            package: "hf2q".into(),
            version: "0.1.7".into(),
            git_commit: "c".repeat(40),
        },
        quant_selector: "q4_k_m".into(),
        output: OutputReceipt {
            path: artifact.display().to_string(),
            size: fs::metadata(artifact).unwrap().len(),
            sha256: compute_file_sha256(artifact).unwrap(),
        },
        excluded_dspark: ExcludedDsparkReceipt {
            tensor_count: 0,
            status: "none_detected".into(),
        },
        peak_chunk_bound: PeakChunkBoundReceipt::default(),
    }
}

fn write_receipt(artifact: &Path, receipt: &ConversionReceipt) {
    fs::write(
        crate::convert::receipt::receipt_path(artifact),
        serde_json::to_vec(receipt).unwrap(),
    )
    .unwrap();
}

#[test]
fn schema_v3_receipt_discovers_nested_local_gguf_for_exact_repository() {
    let root = tempfile::tempdir().unwrap();
    let nested = root.path().join("qwen3.8");
    fs::create_dir(&nested).unwrap();
    let artifact = nested.join("model-q4_k_m.gguf");
    write_q4_k_m_gguf(&artifact);
    write_receipt(&artifact, &receipt_for(&artifact, "owner/model"));

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);

    assert_eq!(catalog.artifacts.len(), 1);
    let found = &catalog.artifacts[0];
    assert_eq!(found.repository, "owner/model");
    assert_eq!(found.path, artifact.canonicalize().unwrap());
    assert_eq!(found.filename, "model-q4_k_m.gguf");
    assert_eq!(found.quant, Some(QuantType::Q4_K_M));
    assert!(found.selectable);
    assert_eq!(found.provenance, LocalArtifactProvenance::ConversionReceipt);
}

#[test]
fn stale_size_wrong_repo_and_symlinks_never_become_candidates() {
    let root = tempfile::tempdir().unwrap();
    let wrong_repo = root.path().join("wrong.gguf");
    write_q4_k_m_gguf(&wrong_repo);
    write_receipt(&wrong_repo, &receipt_for(&wrong_repo, "other/model"));
    let stale = root.path().join("stale.gguf");
    write_q4_k_m_gguf(&stale);
    write_receipt(&stale, &receipt_for(&stale, "owner/model"));
    fs::OpenOptions::new()
        .append(true)
        .open(&stale)
        .unwrap()
        .write_all(b"changed")
        .unwrap();
    #[cfg(unix)]
    {
        let linked = root.path().join("linked.gguf");
        std::os::unix::fs::symlink(&stale, &linked).unwrap();
        write_receipt(&linked, &receipt_for(&stale, "owner/model"));
    }

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);

    assert!(catalog.artifacts.is_empty());
}

#[test]
fn recorded_output_path_is_never_dereferenced() {
    let root = tempfile::tempdir().unwrap();
    let artifact = root.path().join("model.gguf");
    write_q4_k_m_gguf(&artifact);
    let mut receipt = receipt_for(&artifact, "owner/model");
    receipt.output.path = "/private/old/location/../../secret.gguf".into();
    write_receipt(&artifact, &receipt);

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);
    assert_eq!(catalog.artifacts.len(), 1);
    assert_eq!(catalog.artifacts[0].path, artifact.canonicalize().unwrap());
}

#[test]
fn unsupported_receipt_quant_is_visible_but_not_selectable() {
    let root = tempfile::tempdir().unwrap();
    let artifact = root.path().join("model-bf16.gguf");
    write_q4_k_m_gguf(&artifact);
    let mut receipt = receipt_for(&artifact, "owner/model");
    receipt.quant_selector = "bf16".into();
    write_receipt(&artifact, &receipt);

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);
    assert_eq!(catalog.artifacts.len(), 1);
    assert!(!catalog.artifacts[0].selectable);
    assert_eq!(catalog.artifacts[0].quant_hint, "BF16");
    assert!(catalog.artifacts[0]
        .unavailable_reason
        .as_deref()
        .unwrap()
        .contains("mlx-native"));
}

#[test]
fn managed_cache_path_must_equal_canonical_layout() {
    let root = tempfile::tempdir().unwrap();
    let outside = tempfile::NamedTempFile::new().unwrap();
    write_q4_k_m_gguf(outside.path());
    let entry = ModelEntry {
        repo_id: "owner/model".into(),
        revision: "a".repeat(40),
        source: None,
        quantizations: BTreeMap::from([(
            "Q4_K_M".into(),
            QuantEntry {
                quant_type: "Q4_K_M".into(),
                gguf_path: outside.path().to_path_buf(),
                mmproj_path: None,
                bytes: fs::metadata(outside.path()).unwrap().len(),
                sha256: compute_file_sha256(outside.path()).unwrap(),
                quantized_at_secs: 1,
                quantized_by_version: "0.1.7".into(),
            },
        )]),
        last_accessed_secs: 1,
        source_shards: Vec::new(),
    };
    let manifest = CacheManifest {
        schema_version: crate::serve::cache::MANIFEST_SCHEMA_VERSION,
        models: BTreeMap::from([("owner/model".into(), entry)]),
    };

    let catalog = LocalArtifactInventory::default()
        .discover(Some("owner/model"), Some((root.path(), &manifest)));
    assert!(catalog.artifacts.is_empty());
    assert!(catalog
        .warnings
        .iter()
        .any(|warning| warning.contains("canonical layout")));
}

#[test]
fn verifier_rejects_post_catalog_digest_and_quant_changes() {
    let root = tempfile::tempdir().unwrap();
    let artifact = root.path().join("model.gguf");
    write_q4_k_m_gguf(&artifact);
    let sha = compute_file_sha256(&artifact).unwrap();
    let bytes = fs::metadata(&artifact).unwrap().len();
    verify_local_artifact(LocalVerificationRequest {
        root: root.path(),
        artifact: &artifact,
        bytes,
        sha256: &sha,
        quant: QuantType::Q4_K_M,
    })
    .unwrap();

    fs::OpenOptions::new()
        .write(true)
        .open(&artifact)
        .unwrap()
        .write_all(b"NOPE")
        .unwrap();
    let error = verify_local_artifact(LocalVerificationRequest {
        root: root.path(),
        artifact: &artifact,
        bytes,
        sha256: &sha,
        quant: QuantType::Q4_K_M,
    })
    .unwrap_err();
    assert!(error.to_string().contains("SHA-256"));
}

#[test]
fn inventory_observes_a_conventional_root_created_after_server_start() {
    let parent = tempfile::tempdir().unwrap();
    let root = parent.path().join("models");
    let inventory = LocalArtifactInventory::for_test(vec![root.clone()]);
    fs::create_dir(&root).unwrap();
    let artifact = root.join("late.gguf");
    write_q4_k_m_gguf(&artifact);
    write_receipt(&artifact, &receipt_for(&artifact, "owner/model"));

    assert_eq!(
        inventory
            .discover(Some("owner/model"), None)
            .artifacts
            .len(),
        1
    );
}

#[test]
fn inventory_bounds_reject_oversized_receipts_deep_paths_and_excess_roots() {
    let root = tempfile::tempdir().unwrap();

    let oversized = root.path().join("oversized.gguf");
    write_q4_k_m_gguf(&oversized);
    fs::OpenOptions::new()
        .create(true)
        .write(true)
        .open(crate::convert::receipt::receipt_path(&oversized))
        .unwrap()
        .set_len(MAX_RECEIPT_BYTES + 1)
        .unwrap();

    let mut too_deep = root.path().to_path_buf();
    for depth in 0..=MAX_SCAN_DEPTH {
        too_deep.push(format!("depth-{depth}"));
        fs::create_dir(&too_deep).unwrap();
    }
    let deep_artifact = too_deep.join("deep.gguf");
    write_q4_k_m_gguf(&deep_artifact);
    write_receipt(&deep_artifact, &receipt_for(&deep_artifact, "owner/model"));

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);
    assert!(catalog.artifacts.is_empty());
    assert!(catalog
        .warnings
        .iter()
        .any(|warning| warning.contains("oversized")));

    let excess = vec![PathBuf::from("unused"); MAX_ROOTS];
    assert!(LocalArtifactInventory::for_serve(&excess).is_err());
}

#[test]
fn malformed_receipt_authorities_fail_closed() {
    let root = tempfile::tempdir().unwrap();
    let cases = ["schema", "converter", "revision", "digest", "quant"];
    for case in cases {
        let artifact = root.path().join(format!("{case}.gguf"));
        write_q4_k_m_gguf(&artifact);
        let mut receipt = receipt_for(&artifact, "owner/model");
        match case {
            "schema" => receipt.schema_version += 1,
            "converter" => receipt.converter.package = "not-hf2q".into(),
            "revision" => receipt.source.revision = "mutable-main".into(),
            "digest" => receipt.output.sha256 = "not-a-digest".into(),
            "quant" => receipt.quant_selector = "../../Q4_K_M\u{1b}".into(),
            _ => unreachable!(),
        }
        write_receipt(&artifact, &receipt);
    }

    let catalog = LocalArtifactInventory::for_test(vec![root.path().to_path_buf()])
        .discover(Some("owner/model"), None);
    assert!(catalog.artifacts.is_empty());
}

#[test]
fn canonical_managed_cache_artifact_is_selectable() {
    let root = tempfile::tempdir().unwrap();
    let artifact = cache_model_path(root.path(), "owner/model", QuantType::Q4_K_M).unwrap();
    fs::create_dir_all(artifact.parent().unwrap()).unwrap();
    write_q4_k_m_gguf(&artifact);
    let entry = ModelEntry {
        repo_id: "owner/model".into(),
        revision: "a".repeat(40),
        source: None,
        quantizations: BTreeMap::from([(
            "Q4_K_M".into(),
            QuantEntry {
                quant_type: "Q4_K_M".into(),
                gguf_path: artifact.clone(),
                mmproj_path: None,
                bytes: fs::metadata(&artifact).unwrap().len(),
                sha256: compute_file_sha256(&artifact).unwrap(),
                quantized_at_secs: 1,
                quantized_by_version: "0.1.7".into(),
            },
        )]),
        last_accessed_secs: 1,
        source_shards: Vec::new(),
    };
    let manifest = CacheManifest {
        schema_version: crate::serve::cache::MANIFEST_SCHEMA_VERSION,
        models: BTreeMap::from([("owner/model".into(), entry)]),
    };

    let catalog = LocalArtifactInventory::default()
        .discover(Some("owner/model"), Some((root.path(), &manifest)));
    assert_eq!(catalog.artifacts.len(), 1);
    assert_eq!(
        catalog.artifacts[0].provenance,
        LocalArtifactProvenance::ManagedCache
    );
    assert!(catalog.artifacts[0].selectable);
}