use super::*;
use crate::domain::{
CodeFeatureFlagRequest, CodeFileFingerprint, CodeImpactRequest, CodeIndexBatch,
CodeIndexCheckpoint, CodeIndexPublicationFence, CodeIndexResourceBudget, CodeIndexSession,
CodeIndexSnapshot, CodeIndexSummary, CodeIndexTaskRecord, CodeQueryKind,
CodeRepositoryRegistration, CodeRepositorySelector, CodeRepositoryStatus, CodeRetrievalHit,
CodeRetrievalRequest, CodeScopeRetentionSummary, CodebaseViewKind, CodebaseViewRequest,
FreshnessPolicy, SoftwareGlobalKind, SoftwareGlobalRequest,
};
use crate::storage::StorageFuture;
struct MinimalCodeRepositoryStore;
macro_rules! required_code_repository_method {
($name:ident($($argument:ident: $argument_type:ty),*) -> $return_type:ty) => {
fn $name(&self, $($argument: $argument_type),*) -> StorageFuture<'_, $return_type> {
$(let _ = $argument;)*
Box::pin(async { panic!("required method must not be called by default contract tests") })
}
};
}
impl FrameworkGraphStore for MinimalCodeRepositoryStore {}
impl RepositoryCatalogStore for MinimalCodeRepositoryStore {
required_code_repository_method!(upsert_code_repository(registration: CodeRepositoryRegistration) -> CodeRepositoryStatus);
required_code_repository_method!(code_repository_status(repository: String) -> Option<CodeRepositoryStatus>);
required_code_repository_method!(code_repository_scope_status(repository: String, resolved_commit_sha: String, path_filters: Vec<String>, language_filters: Vec<String>) -> Option<CodeRepositoryStatus>);
}
impl CodeIndexTaskStore for MinimalCodeRepositoryStore {
required_code_repository_method!(queue_code_index_task(task: CodeIndexTaskSeed) -> CodeIndexTaskRecord);
required_code_repository_method!(claim_code_index_task(request: CodeIndexTaskClaimRequest) -> Option<CodeIndexTaskRecord>);
required_code_repository_method!(complete_code_index_task(request: CodeIndexTaskCompletion) -> CodeIndexTaskRecord);
required_code_repository_method!(fail_code_index_task(request: CodeIndexTaskFailure) -> CodeIndexTaskRecord);
required_code_repository_method!(code_index_task(task_id: String) -> Option<CodeIndexTaskRecord>);
required_code_repository_method!(active_code_index_task(repository_id: String) -> Option<CodeIndexTaskRecord>);
}
impl CodeIndexPublicationStore for MinimalCodeRepositoryStore {
required_code_repository_method!(code_index_checkpoint(source_scope: String) -> Option<CodeIndexCheckpoint>);
required_code_repository_method!(apply_code_index_snapshot(snapshot: CodeIndexSnapshot) -> CodeIndexSummary);
}
impl CodeScopeRetentionStore for MinimalCodeRepositoryStore {
required_code_repository_method!(code_scope_retention(repository_id: String) -> CodeScopeRetentionSummary);
required_code_repository_method!(prune_code_repository_scopes(request: CodeScopeRetentionRequest) -> CodeScopeRetentionSummary);
}
impl CodeIndexSourceStore for MinimalCodeRepositoryStore {
required_code_repository_method!(code_file_fingerprints(repository_id: String) -> Vec<CodeFileFingerprint>);
}
impl CodeQueryReadStore for MinimalCodeRepositoryStore {
required_code_repository_method!(search_code(request: CodeRetrievalRequest) -> Vec<CodeRetrievalHit>);
required_code_repository_method!(analyze_code_impact(request: CodeImpactRequest, changes: CodeImpactChanges) -> Vec<CodeRetrievalHit>);
}
impl SoftwareProjectionStore for MinimalCodeRepositoryStore {}
impl CodeRepositorySetStore for MinimalCodeRepositoryStore {}
#[tokio::test]
async fn default_code_repository_methods_are_bounded_and_explicit() {
let store = MinimalCodeRepositoryStore;
let selector = code_repository_selector();
let retrieval = CodeRetrievalRequest::new(
"query",
selector.clone(),
CodeQueryKind::Hybrid,
5,
FreshnessPolicy::AllowStale,
)
.expect("retrieval request should validate");
let feature_flags =
CodeFeatureFlagRequest::new(None, selector.clone(), 5, FreshnessPolicy::AllowStale)
.expect("feature flag request should validate");
let impact = CodeImpactRequest::new(selector.clone(), "base", "head", 5)
.expect("impact request should validate");
let view = CodebaseViewRequest::new(
selector.clone(),
CodebaseViewKind::ArchitectureLayers,
FreshnessPolicy::AllowStale,
5,
Vec::new(),
)
.expect("view request should validate");
let software = SoftwareGlobalRequest::new(
selector,
SoftwareGlobalKind::All,
FreshnessPolicy::AllowStale,
5,
)
.expect("software request should validate");
assert_unavailable(
store.list_code_repositories().await,
"code repository catalog listing is unavailable",
);
assert_unavailable(
store
.latest_code_repository_scope_status("repo".to_owned(), Vec::new(), Vec::new())
.await,
"latest code repository scope for 'repo' is unavailable",
);
assert_unavailable(
store.running_code_index_task_leases().await,
"code index task lease inspection is unavailable",
);
assert_unavailable(
store.code_index_task_queue_status().await,
"code index task queue status is unavailable",
);
assert_unavailable(
store
.code_index_publication_receipt(
"task".to_owned(),
"repo".to_owned(),
"scope".to_owned(),
1,
)
.await,
"code index publication receipt for task 'task' is unavailable",
);
assert_unavailable(
store
.reconcile_code_index_publication_with_fence(
CodeIndexPublicationTarget {
task_id: "task".to_owned(),
repository_id: "repo".to_owned(),
source_scope: "scope".to_owned(),
resolved_commit_sha: "commit".to_owned(),
tree_hash: "tree".to_owned(),
path_filters: Vec::new(),
language_filters: Vec::new(),
},
CodeIndexPublicationFence {
repository_id: "repo".to_owned(),
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
generation: 1,
},
)
.await,
"code index publication reconciliation for task 'task' is unavailable",
);
assert_unavailable(
store.latest_code_index_checkpoint("repo".to_owned()).await,
"latest code index checkpoint for repository 'repo' is unavailable",
);
assert_unavailable(
store
.clear_code_workspace_state("repo".to_owned(), "scope".to_owned())
.await,
"workspace cleanup for repository 'repo' scope 'scope' is unavailable",
);
assert_unavailable(
store
.code_repository_auto_workspace_state_exists("repo".to_owned())
.await,
"auto workspace state inspection for repository 'repo' is unavailable",
);
assert_unavailable(
store.code_repository_totals().await,
"code repository totals are unavailable",
);
assert_unavailable(
store.code_repository_set("set".to_owned()).await,
"repository set lookup for 'set' is unavailable",
);
assert_unavailable(
store.code_repository_set_status("set".to_owned()).await,
"repository set status for 'set' is unavailable",
);
assert_unavailable(
store
.code_repository_set_cross_edges("set".to_owned())
.await,
"repository set cross edges for 'set' are unavailable",
);
assert_unavailable(
store
.claim_code_repository_set_refresh_task(CodeRepositorySetRefreshTaskClaimRequest {
task_id: None,
lease_owner: "worker".to_owned(),
lease_duration_ms: 10,
max_attempts: 1,
now_ms: 1,
})
.await,
"repository set refresh task claim is unavailable",
);
assert_unavailable(
store.remove_code_repository("repo".to_owned(), 1).await,
"code repository removal for 'repo' at 1 is unavailable",
);
assert_unavailable(
store.recover_code_index_task_leases(1, 1).await,
CODE_INDEX_TASK_LEASE_RECOVERY_UNAVAILABLE,
);
assert_unavailable(
store
.recover_code_index_task_leases_by_task(CodeIndexTaskLeaseRecovery {
leases: vec![CodeIndexTaskLeaseRecord {
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
lease_expires_at_ms: Some(1),
attempt_count: 1,
publication_generation: 1,
}],
now_ms: 1,
max_attempts: 1,
error_kind: "lease".to_owned(),
error_message: "expired".to_owned(),
})
.await,
CODE_INDEX_TASK_LEASE_RECOVERY_UNAVAILABLE,
);
assert_unavailable(
store.reset_code_index_tasks("repo".to_owned(), 1).await,
"code index task reset is unavailable",
);
assert_unavailable(
store
.renew_code_index_task_lease(CodeIndexTaskLeaseRenewal {
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
publication_generation: 1,
lease_duration_ms: 10,
now_ms: 1,
})
.await,
CODE_INDEX_TASK_LEASE_RENEWAL_UNAVAILABLE,
);
assert_unavailable(
store
.code_file_fingerprints_for_scope("scope".to_owned())
.await,
"code file fingerprints for scope 'scope' are unavailable",
);
assert_unavailable(
store
.code_file_fingerprints_for_paths("scope".to_owned(), vec!["src/lib.rs".to_owned()])
.await,
"code file fingerprints for scope 'scope' are unavailable",
);
assert_unavailable(
store
.code_file_candidate_paths_for_scope(
"scope".to_owned(),
Vec::new(),
Vec::new(),
true,
5,
)
.await,
"bounded code file candidate paths for scope 'scope' are unavailable",
);
assert_unavailable(
store
.code_file_candidate_paths_for_query_scope(
"scope".to_owned(),
"query".to_owned(),
Vec::new(),
Vec::new(),
true,
5,
)
.await,
"bounded code file candidate paths for scope 'scope' are unavailable",
);
assert_unavailable(
store.begin_code_index_session(code_index_session()).await,
"checkpointed code index sessions for scope 'scope' are unavailable",
);
assert_unavailable(
store
.begin_code_index_session_at_checkpoint(code_index_session(), None)
.await,
"checkpoint-CAS session startup for scope 'scope' at expectation 'missing' is unavailable",
);
assert_unavailable(
store
.begin_code_index_session_at_checkpoint_with_fence(
code_index_session(),
None,
CodeIndexPublicationFence {
repository_id: "repo".to_owned(),
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
generation: 1,
},
)
.await,
"attempt-scoped checkpoint-CAS session startup for task 'task' scope 'scope' at expectation 'missing' is unavailable",
);
assert_unavailable(
store.apply_code_index_batch(code_index_batch()).await,
"checkpointed code index batches for scope 'scope' are unavailable",
);
assert_unavailable(
store
.finalize_code_index_session(code_index_session())
.await,
"checkpointed code index finalization for scope 'scope' is unavailable",
);
assert_unavailable(
store
.advance_code_index_session_with_fence(
code_index_session(),
CodeIndexPublicationFence {
repository_id: "repo".to_owned(),
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
generation: 1,
},
)
.await,
"attempt-scoped single-step finalization for task 'task' scope 'scope' is unavailable",
);
assert_unavailable(
store
.run_code_index_post_maintenance("repo".to_owned(), "scope".to_owned())
.await,
"post-index maintenance for repository 'repo' scope 'scope' is unavailable",
);
assert_unavailable(
store.search_code_feature_flags(feature_flags.clone()).await,
"code feature flag search for repository 'repo' is unavailable",
);
assert_unavailable(
store
.search_code_feature_flags_scope("scope".to_owned(), feature_flags)
.await,
"code feature flag search for source scope 'scope' is unavailable",
);
assert_unavailable(
store.search_code_scope("scope".to_owned(), retrieval).await,
"code search for source scope 'scope' is unavailable",
);
assert_unavailable(
store
.analyze_code_impact_scope("scope".to_owned(), impact, CodeImpactChanges::default())
.await,
"code impact analysis for source scope 'scope' is unavailable",
);
assert_unavailable(
store
.codebase_view_snapshot("scope".to_owned(), view, 10)
.await,
"codebase view snapshot for source scope 'scope' is unavailable",
);
assert_unavailable(
store.code_repository_report("repo".to_owned()).await,
"code repository report for 'repo' is unavailable",
);
assert_unavailable(
store
.code_repository_scope_symbol_generation_counts("scope".to_owned())
.await,
"code symbol generation counts for source scope 'scope' are unavailable",
);
assert_unavailable(
store
.refresh_software_global_projection("scope".to_owned())
.await,
"software global projection for source scope 'scope' is unavailable",
);
assert_unavailable(
store.software_global_projection(software.clone()).await,
"software global projection for repository 'repo' is unavailable",
);
assert_unavailable(
store
.software_global_projection_for_scope("scope".to_owned(), software)
.await,
"software global projection for source scope 'scope' is unavailable",
);
assert_unavailable(
store
.create_code_repository_set(CodeRepositorySetSeed {
alias: "set".to_owned(),
description: None,
default_ref_policy_json: "{}".to_owned(),
now_ms: 1,
})
.await,
"repository set storage is unavailable",
);
assert_unavailable(
store
.add_code_repository_set_member(CodeRepositorySetMemberSeed {
set_alias: "set".to_owned(),
repository_id: "repo".to_owned(),
repository_alias: "repo".to_owned(),
ref_selector: "HEAD".to_owned(),
resolved_commit_sha: "commit".to_owned(),
source_scope: "scope".to_owned(),
path_filters: Vec::new(),
language_filters: Vec::new(),
priority: 0,
})
.await,
"repository set member storage is unavailable",
);
assert_unavailable(
store
.remove_code_repository_set_member("set".to_owned(), "repo".to_owned())
.await,
"repository set member storage is unavailable",
);
assert_unavailable(
store
.refresh_code_repository_set_overlay(
"set".to_owned(),
CodeRepositorySetRefreshPublication {
task_id: "task".to_owned(),
set_id: "set-id".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
member_replacements: Vec::new(),
},
)
.await,
"repository set overlay refresh is unavailable",
);
assert_unavailable(
store
.queue_code_repository_set_refresh_task(CodeRepositorySetRefreshTaskSeed {
set_id: "set-id".to_owned(),
set_alias: "set".to_owned(),
input_fingerprint: "fingerprint".to_owned(),
now_ms: 1,
})
.await,
"repository set refresh task storage is unavailable",
);
assert_unavailable(
store
.complete_code_repository_set_refresh_task(CodeRepositorySetRefreshTaskCompletion {
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
now_ms: 1,
})
.await,
"repository set refresh task storage is unavailable",
);
assert_unavailable(
store
.fail_code_repository_set_refresh_task(CodeRepositorySetRefreshTaskFailure {
task_id: "task".to_owned(),
lease_owner: "worker".to_owned(),
attempt_count: 1,
error_kind: "worker".to_owned(),
error_message: "failed".to_owned(),
retry_backoff_ms: 10,
max_attempts: 1,
now_ms: 1,
})
.await,
"repository set refresh task storage is unavailable",
);
}
fn assert_unavailable<T: std::fmt::Debug>(result: Result<T, StorageError>, expected: &str) {
let error = result.expect_err("default method should report unavailable storage");
assert!(error.to_string().contains(expected));
}
fn code_repository_selector() -> CodeRepositorySelector {
CodeRepositorySelector::new("repo", "HEAD", Vec::new(), Vec::new())
.expect("selector should validate")
}
fn code_index_session() -> CodeIndexSession {
CodeIndexSession {
repository_id: "repo".to_owned(),
source_scope: "scope".to_owned(),
base_resolved_commit_sha: None,
resolved_commit_sha: "commit".to_owned(),
tree_hash: "tree".to_owned(),
path_filters: Vec::new(),
language_filters: Vec::new(),
full_replace: true,
total_path_count: 0,
changed_path_count: 0,
skipped_unchanged_count: 0,
deleted_paths: Vec::new(),
changed_paths: Vec::new(),
tombstones: Vec::new(),
workspaces: Vec::new(),
resource_budget: CodeIndexResourceBudget::default(),
}
}
fn code_index_batch() -> CodeIndexBatch {
CodeIndexBatch {
repository_id: "repo".to_owned(),
source_scope: "scope".to_owned(),
batch_index: 0,
parsed_byte_count: 0,
files: Vec::new(),
symbols: Vec::new(),
references: Vec::new(),
imports: Vec::new(),
dependencies: Vec::new(),
feature_flags: Vec::new(),
framework_nodes: Vec::new(),
framework_edges: Vec::new(),
routes: Vec::new(),
chunks: Vec::new(),
diagnostics: Vec::new(),
}
}