mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 08:27:46 +08:00
ci(gateway): slim Test (Gateway) batch 1 — split architecture guards, pin build fingerprint
第一批减负(对应 docs/operations/gateway-ci-timeout-reduction-plan.md): A1 架构守卫迁出 - 将 src/tests/architecture/**(208 项 / 约 1.5 万行字符串断言)迁至 tests/architecture/,入口 tests/architecture_guard.rs - 从 lib cfg(test) 巨型编译单元移除,压低 rustc 峰值与 OOM 风险 - 断言逻辑不变;helper 可见性改为 pub(crate) A2 构建指纹统一 - test_gateway 的 mold RUSTFLAGS / RUST_MIN_STACK / sccache 上移至 job 级 env - rust-ci.yml 全部 toolchain 钉住 1.95.0(与 rust-toolchain.toml、fmt/clippy 一致) - Gateway 独立 cache key,避免 mold 指纹与无 mold job 互相污染 A4 补安全集成测试 - 新增 Test integration targets:cargo nextest run -p aether-gateway --tests - 覆盖 architecture_guard + 此前未执行的 admin_unsigned_identity_headers 验证:architecture_guard + admin_unsigned 209 passed; cargo check -p aether-gateway --lib --tests 通过;cargo fmt --check 通过。 不创建 PR,仅本地分支提交。
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn usage_runtime_paths_depend_on_shared_crates_not_app_runtime_shims() {
|
||||
assert!(
|
||||
!workspace_file_exists("apps/aether-gateway/src/usage/runtime.rs"),
|
||||
"usage/runtime.rs should stay removed after collapsing the runtime shim into usage/mod.rs"
|
||||
);
|
||||
for path in [
|
||||
"apps/aether-gateway/src/usage/config.rs",
|
||||
"apps/aether-gateway/src/usage/queue.rs",
|
||||
"apps/aether-gateway/src/usage/event.rs",
|
||||
] {
|
||||
assert!(
|
||||
!workspace_file_exists(path),
|
||||
"{path} should stay removed after collapsing usage shim modules into usage/mod.rs"
|
||||
);
|
||||
}
|
||||
|
||||
for path in [
|
||||
"apps/aether-gateway/src/usage/mod.rs",
|
||||
"apps/aether-gateway/src/usage/worker.rs",
|
||||
"apps/aether-gateway/src/async_task/runtime.rs",
|
||||
] {
|
||||
let source = read_workspace_file(path);
|
||||
assert!(
|
||||
source.contains("aether_usage_runtime"),
|
||||
"{path} should depend on aether_usage_runtime"
|
||||
);
|
||||
assert!(
|
||||
!source.contains("wallet_runtime"),
|
||||
"{path} should not depend on wallet_runtime"
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let path = "apps/aether-gateway/src/async_task/runtime.rs";
|
||||
let source = read_workspace_file(path);
|
||||
assert!(
|
||||
source.contains("aether_billing"),
|
||||
"{path} should depend on aether_billing"
|
||||
);
|
||||
assert!(
|
||||
!source.contains("billing_runtime::enrich_usage_event_with_billing"),
|
||||
"{path} should not depend on billing_runtime compat re-export"
|
||||
);
|
||||
assert!(
|
||||
!source.contains("settlement_runtime::settle_usage_if_needed"),
|
||||
"{path} should not depend on settlement_runtime compat re-export"
|
||||
);
|
||||
}
|
||||
|
||||
let usage_runtime = read_workspace_file("apps/aether-gateway/src/usage/mod.rs");
|
||||
assert!(
|
||||
!usage_runtime.contains("GatewayDataState"),
|
||||
"usage/mod.rs should not own GatewayDataState integration impls anymore"
|
||||
);
|
||||
assert!(
|
||||
!usage_runtime.contains("UsageBillingEventEnricher"),
|
||||
"usage/mod.rs should not own UsageBillingEventEnricher impl anymore"
|
||||
);
|
||||
assert!(
|
||||
!usage_runtime.contains("UsageRuntimeAccess"),
|
||||
"usage/mod.rs should not own UsageRuntimeAccess impl anymore"
|
||||
);
|
||||
assert!(
|
||||
usage_runtime.contains("pub(crate) use aether_usage_runtime::UsageRuntime;"),
|
||||
"usage/mod.rs should expose UsageRuntime directly from aether_usage_runtime"
|
||||
);
|
||||
for pattern in [
|
||||
"UsageRuntimeConfig",
|
||||
"UsageQueue",
|
||||
"UsageEvent",
|
||||
"UsageEventData",
|
||||
"UsageEventType",
|
||||
"USAGE_EVENT_VERSION",
|
||||
"now_ms",
|
||||
] {
|
||||
assert!(
|
||||
usage_runtime.contains(pattern),
|
||||
"usage/mod.rs should expose usage runtime seam {pattern} directly"
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
!usage_runtime.contains("mod runtime;"),
|
||||
"usage/mod.rs should not keep a local runtime shim module"
|
||||
);
|
||||
for forbidden in ["mod config;", "mod queue;", "mod event;"] {
|
||||
assert!(
|
||||
!usage_runtime.contains(forbidden),
|
||||
"usage/mod.rs should not keep deleted shim module {forbidden}"
|
||||
);
|
||||
}
|
||||
|
||||
let usage_worker = read_workspace_file("apps/aether-gateway/src/usage/worker.rs");
|
||||
let runtime_usage_worker = usage_worker
|
||||
.split("#[cfg(test)]")
|
||||
.next()
|
||||
.unwrap_or(usage_worker.as_str());
|
||||
assert!(
|
||||
!runtime_usage_worker.contains("GatewayDataState"),
|
||||
"usage/worker.rs runtime path should not own GatewayDataState integration impls anymore"
|
||||
);
|
||||
assert!(
|
||||
!runtime_usage_worker.contains("UsageRecordWriter"),
|
||||
"usage/worker.rs runtime path should not own UsageRecordWriter impl anymore"
|
||||
);
|
||||
|
||||
let integrations = read_workspace_file("apps/aether-gateway/src/data/state/integrations.rs");
|
||||
for pattern in [
|
||||
"UsageBillingEventEnricher for GatewayDataState",
|
||||
"UsageRuntimeAccess for GatewayDataState",
|
||||
"UsageRecordWriter for GatewayDataState",
|
||||
"UsageSettlementWriter for GatewayDataState",
|
||||
] {
|
||||
assert!(
|
||||
integrations.contains(pattern),
|
||||
"data/state/integrations.rs should centralize {pattern}"
|
||||
);
|
||||
}
|
||||
|
||||
let usage_reporting_context =
|
||||
read_workspace_file("apps/aether-gateway/src/usage/reporting/context.rs");
|
||||
assert!(
|
||||
usage_reporting_context.contains("aether_usage_runtime"),
|
||||
"usage/reporting/context.rs should depend on aether_usage_runtime"
|
||||
);
|
||||
assert!(
|
||||
usage_reporting_context.contains("resolve_video_task_report_lookup"),
|
||||
"usage/reporting/context.rs should depend on shared video task report lookup helper"
|
||||
);
|
||||
for pattern in [
|
||||
"build_locally_actionable_report_context_from_video_task",
|
||||
"report_context_is_locally_actionable",
|
||||
] {
|
||||
assert!(
|
||||
usage_reporting_context.contains(pattern),
|
||||
"usage/reporting/context.rs should depend on shared usage helper {pattern}"
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
usage_reporting_context.contains("VideoTaskReportLookup::TaskIdOrExternal"),
|
||||
"usage/reporting/context.rs should keep app-local external task fallback orchestration"
|
||||
);
|
||||
for pattern in [
|
||||
"build_locally_actionable_report_context_from_request_candidate",
|
||||
"read_request_candidates_by_request_id(",
|
||||
"resolve_locally_actionable_report_context_from_request_candidates(",
|
||||
] {
|
||||
assert!(
|
||||
!usage_reporting_context.contains(pattern),
|
||||
"usage/reporting/context.rs should not own request-candidate resolver details {pattern}"
|
||||
);
|
||||
}
|
||||
for pattern in [
|
||||
"context\n .get(\"local_task_id\")",
|
||||
"context\n .get(\"local_short_id\")",
|
||||
"context\n .get(\"task_id\")",
|
||||
"VideoTaskLookupKey::ShortId(short_id)",
|
||||
"fn insert_missing_string_value(",
|
||||
"fn insert_missing_optional_string_value(",
|
||||
"fn has_non_empty_str(",
|
||||
"fn has_u64(",
|
||||
] {
|
||||
assert!(
|
||||
!usage_reporting_context.contains(pattern),
|
||||
"usage/reporting/context.rs should not own video task report lookup parsing {pattern}"
|
||||
);
|
||||
}
|
||||
|
||||
let usage_reporting_mod = read_workspace_file("apps/aether-gateway/src/usage/reporting/mod.rs");
|
||||
assert!(
|
||||
usage_reporting_mod.contains("aether_usage_runtime"),
|
||||
"usage/reporting/mod.rs should depend on aether_usage_runtime"
|
||||
);
|
||||
for pattern in [
|
||||
"is_local_ai_sync_report_kind",
|
||||
"is_local_ai_stream_report_kind",
|
||||
"sync_report_represents_failure",
|
||||
"report_request_id",
|
||||
"should_handle_local_sync_report",
|
||||
"should_handle_local_stream_report",
|
||||
"apply_local_report_effect",
|
||||
"LocalReportEffect",
|
||||
] {
|
||||
assert!(
|
||||
usage_reporting_mod.contains(pattern),
|
||||
"usage/reporting/mod.rs should depend on shared usage helper {pattern}"
|
||||
);
|
||||
}
|
||||
for pattern in [
|
||||
"fn is_local_ai_sync_report_kind(",
|
||||
"fn is_local_ai_stream_report_kind(",
|
||||
"fn sync_report_represents_failure(",
|
||||
"fn extract_gemini_file_mapping_entries(",
|
||||
"fn maybe_push_local_gemini_file_mapping_entry(",
|
||||
"fn extract_sync_report_body_json(",
|
||||
"fn content_type_starts_with(",
|
||||
"fn normalize_file_name(",
|
||||
"const GEMINI_FILE_MAPPING_TTL_SECONDS",
|
||||
"const GEMINI_FILE_MAPPING_CACHE_PREFIX",
|
||||
"fn gemini_file_mapping_cache_key(",
|
||||
"fn report_request_id(",
|
||||
"fn should_handle_local_sync_report(",
|
||||
"fn should_handle_local_stream_report(",
|
||||
"\"openai_video_delete_sync_success\" && payload.status_code == 404",
|
||||
"sync_codex_quota_from_response_headers(",
|
||||
"apply_local_gemini_file_mapping_report_effect(",
|
||||
"pub(crate) async fn store_local_gemini_file_mapping(",
|
||||
] {
|
||||
assert!(
|
||||
!usage_reporting_mod.contains(pattern),
|
||||
"usage/reporting/mod.rs should not own local report classification logic {pattern}"
|
||||
);
|
||||
}
|
||||
|
||||
let report_effects =
|
||||
read_workspace_file("apps/aether-gateway/src/orchestration/report_effects.rs");
|
||||
assert!(
|
||||
report_effects.contains("aether_usage_runtime"),
|
||||
"orchestration/report_effects.rs should depend on aether_usage_runtime"
|
||||
);
|
||||
for pattern in [
|
||||
"extract_gemini_file_mapping_entries",
|
||||
"gemini_file_mapping_cache_key",
|
||||
"normalize_gemini_file_name",
|
||||
"report_request_id",
|
||||
"GEMINI_FILE_MAPPING_TTL_SECONDS",
|
||||
"sync_codex_quota_from_response_headers",
|
||||
"store_local_gemini_file_mapping",
|
||||
"delete_local_gemini_file_mapping",
|
||||
"GatewaySyncReportRequest",
|
||||
"GatewayStreamReportRequest",
|
||||
] {
|
||||
assert!(
|
||||
report_effects.contains(pattern),
|
||||
"orchestration/report_effects.rs should own local report effect detail {pattern}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handlers_do_not_depend_on_raw_state_records() {
|
||||
assert_no_sensitive_log_patterns(
|
||||
"src/handlers",
|
||||
&[
|
||||
"StoredUserSessionRecord",
|
||||
"StoredUserPreferenceRecord",
|
||||
"AdminPaymentCallbackRecord",
|
||||
],
|
||||
);
|
||||
|
||||
let state_types = read_workspace_file("apps/aether-gateway/src/state/types.rs");
|
||||
for pattern in [
|
||||
"pub(crate) struct GatewayUserSessionView",
|
||||
"pub(crate) struct GatewayUserPreferenceView",
|
||||
"pub(crate) struct GatewayAdminPaymentCallbackView",
|
||||
] {
|
||||
assert!(
|
||||
state_types.contains(pattern),
|
||||
"state/types.rs should keep handler-facing state view {pattern}"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user