hf2q 0.1.7

Pure Rust CLI for converting HuggingFace models to hardware-optimized formats and serving them over an OpenAI-compatible API on Apple Silicon
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};

use super::*;
use crate::input::hf_download::{
    bind_model_preparation_resolution_for_test, bind_transfer_authorization_for_test,
    ResolvedModelRepository,
};
use crate::input::hf_reference::HfModelReference;
use crate::input::model_recipe::{
    embedded_qwen38_recipe, ModelPreparationPlan, QWEN38_ACCEPTED_REVISION,
};

struct RecordingExecutor {
    snapshot: PathBuf,
    requested: Vec<String>,
    fail_at: Option<usize>,
}

impl PayloadExecutor for RecordingExecutor {
    fn transfer_one(
        &mut self,
        expected: &ShardIntegrity,
    ) -> Result<PathBuf, ModelPreparationPayloadError> {
        if self.fail_at == Some(self.requested.len()) {
            return Err(DownloadError::DownloadFailed {
                reason: "injected transfer failure".to_owned(),
            }
            .into());
        }
        self.requested.push(expected.filename.clone());
        Ok(self.snapshot.join(&expected.filename))
    }
}

fn authorized(root: &Path) -> AuthorizedModelPreparationTransfer {
    let reference = HfModelReference::parse("Qwen/Qwen3.8-27B", None).unwrap();
    let recipe = embedded_qwen38_recipe().unwrap();
    let plan = ModelPreparationPlan::for_test(
        reference.clone(),
        root,
        "aarch64-apple-darwin",
        "Apple M5 Max",
        128 * 1024 * 1024 * 1024,
        recipe.minimum_free_bytes(),
    )
    .unwrap();
    let inventory = recipe
        .source()
        .files()
        .iter()
        .map(|file| file.path().to_owned())
        .collect::<BTreeSet<_>>();
    let resolution = ResolvedModelRepository::for_test(
        reference.resolve(QWEN38_ACCEPTED_REVISION).unwrap(),
        inventory,
    );
    let resolved = bind_model_preparation_resolution_for_test(plan, resolution).unwrap();
    let records = recipe
        .source()
        .files()
        .iter()
        .map(|file| ShardIntegrity {
            filename: file.path().to_owned(),
            bytes: file.size(),
            sha256: file.hf_lfs_sha256().map(str::to_owned),
            hf_etag: file.hub_etag().to_owned(),
            is_lfs: file.hf_lfs_sha256().is_some(),
        })
        .collect();
    bind_transfer_authorization_for_test(resolved, records).unwrap()
}

#[test]
fn payload_transfer_consumes_the_exact_recipe_order_and_stays_inert() {
    let temp = tempfile::tempdir().unwrap();
    let authorized = authorized(temp.path());
    let repo = Repo::with_revision(
        "Qwen/Qwen3.8-27B".to_owned(),
        RepoType::Model,
        QWEN38_ACCEPTED_REVISION.to_owned(),
    );
    let snapshot = authorized
        .source_root()
        .join(repo.folder_name())
        .join("snapshots")
        .join(QWEN38_ACCEPTED_REVISION);
    std::fs::create_dir_all(&snapshot).unwrap();
    let mut executor = RecordingExecutor {
        snapshot: snapshot.clone(),
        requested: Vec::new(),
        fail_at: None,
    };
    let mut completed = 0usize;
    let transferred =
        transfer_with_executor(authorized, &snapshot, &mut executor, || completed += 1).unwrap();
    let expected = embedded_qwen38_recipe()
        .unwrap()
        .source()
        .files()
        .iter()
        .map(|file| file.path().to_owned())
        .collect::<Vec<_>>();
    assert_eq!(executor.requested, expected);
    assert_eq!(completed, 29);
    assert_eq!(transferred.transferred_file_count(), 29);
    assert_eq!(transferred.recipe_id(), "qwen38-27b-official-v1");
    assert!(!format!("{transferred:?}").contains("model-00001"));
}

#[test]
fn failed_or_cross_cache_transfer_mints_no_payload() {
    let temp = tempfile::tempdir().unwrap();
    let initial = authorized(temp.path());
    let source = initial.source_root().to_path_buf();
    let snapshot = source
        .join("models--Qwen--Qwen3.8-27B")
        .join("snapshots")
        .join(QWEN38_ACCEPTED_REVISION);
    std::fs::create_dir_all(&snapshot).unwrap();
    let mut failed = RecordingExecutor {
        snapshot: snapshot.clone(),
        requested: Vec::new(),
        fail_at: Some(7),
    };
    assert!(transfer_with_executor(initial, &snapshot, &mut failed, || {}).is_err());
    assert_eq!(failed.requested.len(), 7);

    let authorized = authorized(temp.path());
    let escaped = temp
        .path()
        .join("elsewhere")
        .join("snapshots")
        .join(QWEN38_ACCEPTED_REVISION);
    std::fs::create_dir_all(&escaped).unwrap();
    let mut executor = RecordingExecutor {
        snapshot: escaped,
        requested: Vec::new(),
        fail_at: None,
    };
    assert!(transfer_with_executor(authorized, &snapshot, &mut executor, || {}).is_err());
}

#[test]
fn namespace_change_is_rejected_before_hub_or_payload_authority() {
    use std::os::unix::fs::symlink;

    let temp = tempfile::tempdir().unwrap();
    let authorized = authorized(temp.path());
    let outside = tempfile::tempdir().unwrap();
    let namespace = temp.path().join("huggingface");
    symlink(outside.path(), &namespace).unwrap();
    let error =
        transfer_authorized_model_preparation(authorized, &ProgressReporter::new()).unwrap_err();
    assert!(error
        .to_string()
        .contains("source root changed after the plan was sealed"));
    assert!(std::fs::read_dir(outside.path()).unwrap().next().is_none());
}

#[test]
fn current_recipe_payload_transfers_and_verifies_when_explicitly_requested() {
    if std::env::var_os("HF2Q_TEST_QWEN38_PAYLOAD_TRANSFER").is_none() {
        return;
    }
    let models_root = PathBuf::from(
        std::env::var_os("HF2Q_TEST_QWEN38_MODELS_ROOT")
            .expect("HF2Q_TEST_QWEN38_MODELS_ROOT must name a persistent absolute directory"),
    );
    let reference = HfModelReference::parse("Qwen/Qwen3.8-27B", None).unwrap();
    let planned =
        crate::input::model_recipe::plan_current_model_preparation(reference, &models_root)
            .unwrap();
    let resolved = crate::input::hf_download::resolve_model_preparation_plan(planned).unwrap();
    let authorized =
        crate::input::hf_download::authorize_model_preparation_transfer(resolved).unwrap();
    let transferred = transfer_authorized_model_preparation(
        authorized,
        &crate::progress::ProgressReporter::new(),
    )
    .unwrap();
    assert_eq!(transferred.transferred_file_count(), 29);
    assert!(transferred.model_root().join("source").is_dir());
}