github source v1
This commit is contained in:
parent
71f89dde9c
commit
caf870d05e
50 changed files with 4139 additions and 131 deletions
|
|
@ -1,3 +1,4 @@
|
|||
use aim_core::adapters::github::GitHubAdapter;
|
||||
use aim_core::adapters::traits::AdapterCapabilities;
|
||||
|
||||
#[test]
|
||||
|
|
@ -5,3 +6,13 @@ fn adapter_capabilities_can_report_exact_resolution_only() {
|
|||
let capabilities = AdapterCapabilities::exact_resolution_only();
|
||||
assert!(!capabilities.supports_search);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_github_adapter_delegates_to_source_pipeline() {
|
||||
let adapter = GitHubAdapter;
|
||||
|
||||
let result = adapter.normalize("sharkdp/bat").unwrap();
|
||||
|
||||
assert_eq!(result.normalized_kind.as_str(), "github-repository");
|
||||
assert_eq!(result.canonical_locator.as_deref(), Some("sharkdp/bat"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use aim_core::adapters::all_adapter_kinds;
|
|||
fn all_expected_adapter_kinds_are_registered() {
|
||||
let kinds = all_adapter_kinds();
|
||||
|
||||
assert!(kinds.contains(&"github"));
|
||||
assert!(kinds.contains(&"gitlab"));
|
||||
assert!(kinds.contains(&"direct-url"));
|
||||
assert!(kinds.contains(&"zsync"));
|
||||
|
|
|
|||
3
crates/aim-core/tests/fixtures/example.zsync
vendored
Normal file
3
crates/aim-core/tests/fixtures/example.zsync
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
zsync: 0.6.2
|
||||
Filename: T3-Code-0.0.11-x86_64.AppImage
|
||||
URL: https://example.test/T3-Code-0.0.11-x86_64.AppImage
|
||||
3
crates/aim-core/tests/fixtures/latest-linux.yml
vendored
Normal file
3
crates/aim-core/tests/fixtures/latest-linux.yml
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version: 0.0.11
|
||||
path: T3-Code-0.0.11-x86_64.AppImage
|
||||
sha512: example-sha
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use aim_core::app::add::build_add_plan;
|
||||
use aim_core::app::add::{build_add_plan_with, materialize_app_record, prefer_latest_tracking};
|
||||
use aim_core::app::query::resolve_query;
|
||||
use aim_core::source::github::FixtureGitHubTransport;
|
||||
|
||||
#[test]
|
||||
fn github_adapter_can_normalize_owner_repo_source() {
|
||||
|
|
@ -10,9 +11,78 @@ fn github_adapter_can_normalize_owner_repo_source() {
|
|||
|
||||
#[test]
|
||||
fn add_flow_builds_github_plan_from_owner_repo_query() {
|
||||
let plan = build_add_plan("sharkdp/bat").unwrap();
|
||||
let plan = build_add_plan_with("sharkdp/bat", &FixtureGitHubTransport).unwrap();
|
||||
|
||||
assert_eq!(plan.resolution.source.kind.as_str(), "github");
|
||||
assert_eq!(plan.resolution.source.locator, "sharkdp/bat");
|
||||
assert_eq!(plan.resolution.release.version, "latest");
|
||||
assert_eq!(plan.selected_artifact.selection_reason, "metadata-guided");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_plan_prefers_metadata_guided_appimage_when_available() {
|
||||
let plan = build_add_plan_with("pingdotgg/t3code", &FixtureGitHubTransport).unwrap();
|
||||
|
||||
assert_eq!(plan.selected_artifact.selection_reason, "metadata-guided");
|
||||
assert_eq!(
|
||||
plan.update_strategy.preferred.kind.as_str(),
|
||||
"electron-builder"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_old_release_url_requests_tracking_choice_prompt() {
|
||||
let plan = build_add_plan_with(
|
||||
"https://github.com/pingdotgg/t3code/releases/download/v0.0.11/T3-Code-0.0.11-x86_64.AppImage",
|
||||
&FixtureGitHubTransport,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
plan.interactions
|
||||
.iter()
|
||||
.any(|item| item.key == "tracking-preference")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn materialized_record_preserves_source_and_strategy() {
|
||||
let query = "sharkdp/bat";
|
||||
let plan = build_add_plan_with(query, &FixtureGitHubTransport).unwrap();
|
||||
|
||||
let record = materialize_app_record(query, &plan).unwrap();
|
||||
|
||||
assert_eq!(record.stable_id, "sharkdp-bat");
|
||||
assert_eq!(record.display_name, "bat");
|
||||
assert_eq!(record.source_input.as_deref(), Some(query));
|
||||
assert_eq!(record.installed_version.as_deref(), Some("1.0.0"));
|
||||
assert_eq!(
|
||||
record
|
||||
.update_strategy
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.preferred
|
||||
.kind
|
||||
.as_str(),
|
||||
"electron-builder"
|
||||
);
|
||||
assert_eq!(record.source.as_ref().unwrap().locator, query);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_tracking_choice_promotes_non_direct_update_channel() {
|
||||
let plan = build_add_plan_with(
|
||||
"https://github.com/pingdotgg/t3code/releases/download/v0.0.11/T3-Code-0.0.11-x86_64.AppImage",
|
||||
&FixtureGitHubTransport,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let resolved = prefer_latest_tracking(plan);
|
||||
|
||||
assert!(resolved.interactions.is_empty());
|
||||
assert_eq!(resolved.resolution.source.locator, "pingdotgg/t3code");
|
||||
assert!(resolved.resolution.source.tracks_latest);
|
||||
assert_ne!(
|
||||
resolved.update_strategy.preferred.kind.as_str(),
|
||||
"direct-asset-lineage"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
33
crates/aim-core/tests/github_source_discovery.rs
Normal file
33
crates/aim-core/tests/github_source_discovery.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use aim_core::app::query::resolve_query;
|
||||
use aim_core::source::github::{FixtureGitHubTransport, discover_github_candidates_with};
|
||||
|
||||
#[test]
|
||||
fn discovery_reports_appimage_assets_and_latest_linux_yml() {
|
||||
let source = resolve_query("pingdotgg/t3code").unwrap();
|
||||
let discovery = discover_github_candidates_with(&source, &FixtureGitHubTransport).unwrap();
|
||||
|
||||
assert!(
|
||||
discovery
|
||||
.assets
|
||||
.iter()
|
||||
.any(|asset| asset.name.ends_with(".AppImage"))
|
||||
);
|
||||
assert!(
|
||||
discovery
|
||||
.metadata_documents
|
||||
.iter()
|
||||
.any(|doc| doc.url.ends_with("latest-linux.yml"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn discovery_marks_explicit_older_release_against_latest_fixture_release() {
|
||||
let source = resolve_query(
|
||||
"https://github.com/pingdotgg/t3code/releases/download/v0.0.11/T3-Code-0.0.11-x86_64.AppImage",
|
||||
)
|
||||
.unwrap();
|
||||
let discovery = discover_github_candidates_with(&source, &FixtureGitHubTransport).unwrap();
|
||||
|
||||
assert_eq!(discovery.releases[0].tag, "v0.0.12");
|
||||
assert!(discovery.requested_is_older_release);
|
||||
}
|
||||
11
crates/aim-core/tests/metadata_contract.rs
Normal file
11
crates/aim-core/tests/metadata_contract.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use aim_core::domain::update::ParsedMetadataKind;
|
||||
use aim_core::metadata::{MetadataDocument, parse_document};
|
||||
|
||||
#[test]
|
||||
fn unknown_document_returns_typed_warning_not_panic() {
|
||||
let doc = MetadataDocument::plain_text("https://example.test/notes.txt", b"not metadata");
|
||||
let result = parse_document(&doc).unwrap();
|
||||
|
||||
assert_eq!(result.kind, ParsedMetadataKind::Unknown);
|
||||
assert!(!result.warnings.is_empty());
|
||||
}
|
||||
15
crates/aim-core/tests/metadata_electron_builder.rs
Normal file
15
crates/aim-core/tests/metadata_electron_builder.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use aim_core::domain::update::ParsedMetadataKind;
|
||||
use aim_core::metadata::{MetadataDocument, parse_document};
|
||||
|
||||
#[test]
|
||||
fn parses_latest_linux_yml_into_download_hints() {
|
||||
let raw = include_bytes!("fixtures/latest-linux.yml");
|
||||
let doc = MetadataDocument::yaml("https://example.test/latest-linux.yml", raw);
|
||||
let result = parse_document(&doc).unwrap();
|
||||
|
||||
assert_eq!(result.kind, ParsedMetadataKind::ElectronBuilder);
|
||||
assert_eq!(
|
||||
result.hints.primary_download.as_deref(),
|
||||
Some("T3-Code-0.0.11-x86_64.AppImage")
|
||||
);
|
||||
}
|
||||
12
crates/aim-core/tests/metadata_zsync.rs
Normal file
12
crates/aim-core/tests/metadata_zsync.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use aim_core::domain::update::ParsedMetadataKind;
|
||||
use aim_core::metadata::{MetadataDocument, parse_document};
|
||||
|
||||
#[test]
|
||||
fn parses_zsync_document_into_channel_hints() {
|
||||
let raw = include_bytes!("fixtures/example.zsync");
|
||||
let doc = MetadataDocument::plain_text("https://example.test/app.AppImage.zsync", raw);
|
||||
let result = parse_document(&doc).unwrap();
|
||||
|
||||
assert_eq!(result.kind, ParsedMetadataKind::Zsync);
|
||||
assert!(result.hints.primary_download.is_some());
|
||||
}
|
||||
|
|
@ -1,8 +1,27 @@
|
|||
use aim_core::app::query::resolve_query;
|
||||
use aim_core::domain::source::SourceKind;
|
||||
use aim_core::domain::source::{NormalizedSourceKind, SourceInputKind, SourceKind};
|
||||
|
||||
#[test]
|
||||
fn owner_repo_defaults_to_github() {
|
||||
let source = resolve_query("sharkdp/bat").unwrap();
|
||||
assert_eq!(source.kind, SourceKind::GitHub);
|
||||
assert_eq!(source.input_kind, SourceInputKind::RepoShorthand);
|
||||
assert_eq!(
|
||||
source.normalized_kind,
|
||||
NormalizedSourceKind::GitHubRepository
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_github_release_asset_url() {
|
||||
let source = resolve_query(
|
||||
"https://github.com/pingdotgg/t3code/releases/download/v0.0.11/T3-Code-0.0.11-x86_64.AppImage",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(source.input_kind, SourceInputKind::GitHubReleaseAssetUrl);
|
||||
assert_eq!(
|
||||
source.normalized_kind,
|
||||
NormalizedSourceKind::GitHubReleaseAsset
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,46 @@ fn registry_round_trips_app_records() {
|
|||
let loaded = store.load().unwrap();
|
||||
assert!(loaded.apps.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_round_trips_update_strategy_and_alternates() {
|
||||
let dir = tempdir().unwrap();
|
||||
let store = RegistryStore::new(dir.path().join("registry.toml"));
|
||||
let registry = aim_core::registry::model::Registry {
|
||||
version: 1,
|
||||
apps: vec![aim_core::domain::app::AppRecord {
|
||||
stable_id: "t3code".to_owned(),
|
||||
display_name: "T3 Code".to_owned(),
|
||||
source_input: Some("pingdotgg/t3code".to_owned()),
|
||||
source: None,
|
||||
installed_version: Some("0.0.11".to_owned()),
|
||||
update_strategy: Some(aim_core::domain::update::UpdateStrategy {
|
||||
preferred: aim_core::domain::update::ChannelPreference {
|
||||
kind: aim_core::domain::update::UpdateChannelKind::DirectAsset,
|
||||
locator: "https://example.test/app.AppImage".to_owned(),
|
||||
reason: "install-origin-match".to_owned(),
|
||||
},
|
||||
alternates: vec![
|
||||
aim_core::domain::update::ChannelPreference {
|
||||
kind: aim_core::domain::update::UpdateChannelKind::GitHubReleases,
|
||||
locator: "pingdotgg/t3code".to_owned(),
|
||||
reason: "heuristic-match".to_owned(),
|
||||
},
|
||||
aim_core::domain::update::ChannelPreference {
|
||||
kind: aim_core::domain::update::UpdateChannelKind::ElectronBuilder,
|
||||
locator: "https://example.test/latest-linux.yml".to_owned(),
|
||||
reason: "metadata-guided".to_owned(),
|
||||
},
|
||||
],
|
||||
}),
|
||||
metadata: Vec::new(),
|
||||
}],
|
||||
};
|
||||
|
||||
store.save(®istry).unwrap();
|
||||
let loaded = store.load().unwrap();
|
||||
|
||||
let strategy = loaded.apps[0].update_strategy.as_ref().unwrap();
|
||||
assert_eq!(strategy.preferred.reason, "install-origin-match");
|
||||
assert_eq!(strategy.alternates.len(), 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use aim_core::app::interaction::InteractionRequest;
|
||||
use aim_core::app::interaction::{InteractionKind, InteractionRequest};
|
||||
use aim_core::app::list::build_list_rows;
|
||||
use aim_core::app::remove::resolve_registered_app;
|
||||
use aim_core::domain::app::AppRecord;
|
||||
|
|
@ -15,6 +15,11 @@ fn list_flow_returns_display_rows_for_registered_apps() {
|
|||
let rows = build_list_rows(&[AppRecord {
|
||||
stable_id: "bat".to_owned(),
|
||||
display_name: "Bat".to_owned(),
|
||||
source_input: None,
|
||||
source: None,
|
||||
installed_version: None,
|
||||
update_strategy: None,
|
||||
metadata: Vec::new(),
|
||||
}]);
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
|
|
@ -28,10 +33,20 @@ fn ambiguous_remove_matches_include_stable_ids_for_client_choice() {
|
|||
AppRecord {
|
||||
stable_id: "bat".to_owned(),
|
||||
display_name: "Bat".to_owned(),
|
||||
source_input: None,
|
||||
source: None,
|
||||
installed_version: None,
|
||||
update_strategy: None,
|
||||
metadata: Vec::new(),
|
||||
},
|
||||
AppRecord {
|
||||
stable_id: "bat-nightly".to_owned(),
|
||||
display_name: "Bat".to_owned(),
|
||||
source_input: None,
|
||||
source: None,
|
||||
installed_version: None,
|
||||
update_strategy: None,
|
||||
metadata: Vec::new(),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -40,9 +55,12 @@ fn ambiguous_remove_matches_include_stable_ids_for_client_choice() {
|
|||
assert_eq!(
|
||||
error,
|
||||
aim_core::app::remove::ResolveRegisteredAppError::Ambiguous {
|
||||
request: InteractionRequest::SelectRegisteredApp {
|
||||
query: "Bat".to_owned(),
|
||||
matches: vec!["Bat (bat)".to_owned(), "Bat (bat-nightly)".to_owned()],
|
||||
request: InteractionRequest {
|
||||
key: "select-registered-app".to_owned(),
|
||||
kind: InteractionKind::SelectRegisteredApp {
|
||||
query: "Bat".to_owned(),
|
||||
matches: vec!["Bat (bat)".to_owned(), "Bat (bat-nightly)".to_owned()],
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use aim_core::app::update::build_update_plan;
|
||||
use aim_core::domain::app::AppRecord;
|
||||
use aim_core::domain::update::{ChannelPreference, UpdateChannelKind, UpdateStrategy};
|
||||
|
||||
#[test]
|
||||
fn empty_registry_produces_empty_plan() {
|
||||
|
|
@ -13,10 +14,48 @@ fn installed_apps_are_carried_into_review_plan() {
|
|||
let apps = [AppRecord {
|
||||
stable_id: "bat".to_owned(),
|
||||
display_name: "Bat".to_owned(),
|
||||
source_input: None,
|
||||
source: None,
|
||||
installed_version: None,
|
||||
update_strategy: None,
|
||||
metadata: Vec::new(),
|
||||
}];
|
||||
|
||||
let plan = build_update_plan(&apps).unwrap();
|
||||
|
||||
assert_eq!(plan.items.len(), 1);
|
||||
assert_eq!(plan.items[0].stable_id, "bat");
|
||||
assert_eq!(plan.items[0].selection_reason, "install-origin-match");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_plan_uses_alternate_channel_after_preferred_failure() {
|
||||
let apps = [AppRecord {
|
||||
stable_id: "t3code".to_owned(),
|
||||
display_name: "T3 Code".to_owned(),
|
||||
source_input: Some("pingdotgg/t3code".to_owned()),
|
||||
source: None,
|
||||
installed_version: Some("0.0.11".to_owned()),
|
||||
update_strategy: Some(UpdateStrategy {
|
||||
preferred: ChannelPreference {
|
||||
kind: UpdateChannelKind::GitHubReleases,
|
||||
locator: "fail://github".to_owned(),
|
||||
reason: "install-origin-match".to_owned(),
|
||||
},
|
||||
alternates: vec![ChannelPreference {
|
||||
kind: UpdateChannelKind::ElectronBuilder,
|
||||
locator: "https://example.test/latest-linux.yml".to_owned(),
|
||||
reason: "metadata-guided".to_owned(),
|
||||
}],
|
||||
}),
|
||||
metadata: Vec::new(),
|
||||
}];
|
||||
|
||||
let plan = build_update_plan(&apps).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
plan.items[0].selected_channel.kind.as_str(),
|
||||
"electron-builder"
|
||||
);
|
||||
assert_eq!(plan.items[0].selection_reason, "preferred-channel-failed");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue