magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::super::refresh::{
    AUTOMATIC_REFRESH_COOLDOWN, automatic_refresh_allowed_at, automatic_refresh_failed_at,
    catalog_refresh_outcome_for_selected_model,
};
use super::super::types::ModelCatalogEntry;
use super::super::{
    CatalogRefreshFailureCategory, CatalogRefreshOutcome, automatic_refresh_allowed,
    automatic_refresh_failed, automatic_refresh_suppressed, refresh_catalog_for_provider,
};
use crate::config::McPaths;
use std::time::{Duration, Instant};
use tempfile::TempDir;

#[test]
fn automatic_refresh_failure_gate_bounds_retries_per_provider() {
    let provider = "automatic-refresh-test-provider";
    assert!(automatic_refresh_allowed(provider));
    automatic_refresh_failed(provider);
    assert!(!automatic_refresh_allowed(provider));
    assert!(automatic_refresh_allowed("another-refresh-provider"));
}

#[test]
fn automatic_refresh_outcome_tracks_selected_model_after_partial_match() {
    let matched = {
        let mut entry = ModelCatalogEntry::new("local-ai", "matched");
        entry.supports_reasoning = Some(true);
        entry
    };
    let unmatched = ModelCatalogEntry::new("local-ai", "selected-unmatched");
    let entries = vec![matched, unmatched];

    assert_eq!(
        catalog_refresh_outcome_for_selected_model(&entries, "local-ai", "selected-unmatched"),
        CatalogRefreshOutcome::NoMatch
    );
    assert_eq!(
        catalog_refresh_outcome_for_selected_model(&entries, "local-ai", "matched"),
        CatalogRefreshOutcome::Updated
    );

    let provider = "selected-model-partial-match-provider";
    assert!(automatic_refresh_allowed(provider));
    automatic_refresh_suppressed(provider);
    assert!(!automatic_refresh_allowed(provider));
}

#[test]
fn automatic_refresh_no_match_gate_bounds_retries_without_affecting_explicit_refresh() {
    let provider = "automatic-no-match-test-provider";
    assert!(automatic_refresh_allowed(provider));
    automatic_refresh_suppressed(provider);
    assert!(!automatic_refresh_allowed(provider));
    automatic_refresh_failed_at(provider, Instant::now() - AUTOMATIC_REFRESH_COOLDOWN);
    assert!(automatic_refresh_allowed(provider));
}

#[test]
fn automatic_refresh_recovery_gate_is_deterministic_without_sleeping() {
    let provider = "deterministic-refresh-provider";
    let failed_at = Instant::now();
    automatic_refresh_failed_at(provider, failed_at);
    assert!(!automatic_refresh_allowed_at(provider, failed_at));
    assert!(!automatic_refresh_allowed_at(
        provider,
        failed_at + AUTOMATIC_REFRESH_COOLDOWN - Duration::from_millis(1)
    ));
    assert!(automatic_refresh_allowed_at(
        provider,
        failed_at + AUTOMATIC_REFRESH_COOLDOWN
    ));
}

#[test]
fn refresh_failure_reports_safe_settings_category() {
    let temp = TempDir::new().unwrap();
    std::fs::create_dir_all(temp.path().join("mc")).unwrap();
    let paths = McPaths::from_root(temp.path().join("mc"));
    std::fs::write(&paths.settings_file, "not json").unwrap();

    let error =
        refresh_catalog_for_provider(&paths, "custom-provider", "selected-model").unwrap_err();
    assert_eq!(error.category(), CatalogRefreshFailureCategory::Settings);
    assert_eq!(
        error.to_string(),
        "settings refresh failed for provider 'custom-provider'"
    );
}