use socket_patch_core::api::blob_fetcher::{
fetch_blobs_by_hash, fetch_missing_blobs, fetch_missing_sources, get_missing_archives,
get_missing_blobs, DownloadMode,
};
use socket_patch_core::api::client::{ApiClient, ApiClientOptions};
use socket_patch_core::manifest::schema::PatchManifest;
use socket_patch_core::patch::apply::PatchSources;
use std::collections::HashSet;
use std::path::Path;
fn dummy_client() -> ApiClient {
ApiClient::new(ApiClientOptions {
api_url: "http://127.0.0.1:1".to_string(),
api_token: None,
use_public_proxy: true,
org_slug: None,
})
}
#[tokio::test]
async fn fetch_missing_blobs_empty_manifest_short_circuits() {
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let manifest = PatchManifest::new();
let client = dummy_client();
let result = fetch_missing_blobs(&manifest, &blobs, &client, None).await;
assert_eq!(result.total, 0);
assert_eq!(result.downloaded, 0);
assert_eq!(result.failed, 0);
assert!(result.results.is_empty());
}
#[tokio::test]
async fn fetch_blobs_by_hash_empty_set_short_circuits() {
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let hashes: HashSet<String> = HashSet::new();
let client = dummy_client();
let result = fetch_blobs_by_hash(&hashes, &blobs, &client, None).await;
assert_eq!(result.total, 0);
assert_eq!(result.downloaded, 0);
assert_eq!(result.failed, 0);
assert!(result.results.is_empty());
}
#[tokio::test]
async fn get_missing_archives_empty_manifest_returns_empty_set() {
let tmp = tempfile::tempdir().unwrap();
let archives_dir = tmp.path().join("archives");
std::fs::create_dir(&archives_dir).unwrap();
let manifest = PatchManifest::new();
let missing = get_missing_archives(&manifest, &archives_dir).await;
assert!(missing.is_empty());
}
#[tokio::test]
async fn fetch_missing_sources_package_mode_with_no_packages_path() {
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let sources = PatchSources {
blobs_path: &blobs,
packages_path: None,
diffs_path: None,
};
let manifest = PatchManifest::new();
let client = dummy_client();
let result =
fetch_missing_sources(&manifest, &sources, DownloadMode::Package, &client, None).await;
assert_eq!(result.total, 0);
assert_eq!(result.downloaded, 0);
assert_eq!(result.failed, 0);
}
#[tokio::test]
async fn fetch_missing_sources_diff_mode_with_no_diffs_path() {
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let sources = PatchSources {
blobs_path: &blobs,
packages_path: None,
diffs_path: None,
};
let manifest = PatchManifest::new();
let client = dummy_client();
let result =
fetch_missing_sources(&manifest, &sources, DownloadMode::Diff, &client, None).await;
assert_eq!(result.total, 0);
}
#[test]
fn download_mode_parse_covers_all_branches() {
assert!(matches!(
DownloadMode::parse("diff"),
Ok(DownloadMode::Diff)
));
assert!(matches!(
DownloadMode::parse("package"),
Ok(DownloadMode::Package)
));
assert!(matches!(
DownloadMode::parse("file"),
Ok(DownloadMode::File)
));
assert!(matches!(
DownloadMode::parse("blob"),
Ok(DownloadMode::File)
));
assert!(matches!(
DownloadMode::parse("DIFF"),
Ok(DownloadMode::Diff)
));
assert!(matches!(
DownloadMode::parse("Package"),
Ok(DownloadMode::Package)
));
assert!(DownloadMode::parse("invalid").is_err());
assert!(DownloadMode::parse("").is_err());
}
#[test]
fn download_mode_as_tag_round_trips_with_parse() {
for mode in [
DownloadMode::Diff,
DownloadMode::Package,
DownloadMode::File,
] {
let tag = mode.as_tag();
assert_eq!(DownloadMode::parse(tag).unwrap(), mode);
}
}
#[allow(dead_code)]
fn _path_marker(_p: &Path) {}
#[tokio::test]
async fn fetch_blobs_by_hash_skips_existing_blobs() {
use std::collections::HashSet;
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let hash = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
std::fs::write(blobs.join(hash), b"already here").unwrap();
let mut hashes = HashSet::new();
hashes.insert(hash.to_string());
let client = dummy_client();
let result = fetch_blobs_by_hash(&hashes, &blobs, &client, None).await;
assert_eq!(result.total, 1, "one hash requested");
assert_eq!(result.downloaded, 0, "already-on-disk needs no download");
assert_eq!(result.skipped, 1, "exactly one skipped");
assert_eq!(result.failed, 0);
assert!(result.results.iter().any(|r| r.success && r.hash == hash));
}
#[tokio::test]
async fn get_missing_blobs_empty_manifest_returns_empty_set() {
let tmp = tempfile::tempdir().unwrap();
let blobs = tmp.path().join("blobs");
std::fs::create_dir(&blobs).unwrap();
let manifest = PatchManifest::new();
let missing = get_missing_blobs(&manifest, &blobs).await;
assert!(missing.is_empty());
}