test(gateway): align CI fixtures with routing contracts

This commit is contained in:
ZheFox
2026-09-04 13:54:50 +08:00
parent 03f2914044
commit ba11a72214
7 changed files with 43 additions and 22 deletions
@@ -1,6 +1,5 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use aether_ai_formats::openai_responses_message_item_id;
use axum::body::to_bytes; use axum::body::to_bytes;
use base64::Engine as _; use base64::Engine as _;
use serde_json::json; use serde_json::json;
@@ -12,10 +11,10 @@ use super::{
convert_gemini_chat_response_to_openai_chat, convert_gemini_response_to_openai_responses, convert_gemini_chat_response_to_openai_chat, convert_gemini_response_to_openai_responses,
maybe_build_local_core_sync_finalize_response, maybe_build_local_core_sync_finalize_response,
}; };
use crate::ai_serving::GatewayControlDecision;
use crate::ai_serving::{ use crate::ai_serving::{
convert_openai_chat_response_to_openai_responses, convert_openai_chat_response_to_openai_responses,
convert_openai_responses_response_to_openai_chat, convert_openai_responses_response_to_openai_chat, openai_responses_message_item_id,
GatewayControlDecision,
}; };
use crate::usage::GatewaySyncReportRequest; use crate::usage::GatewaySyncReportRequest;
@@ -1963,8 +1963,9 @@ fn admin_provider_oauth_quota_mod_stays_thin() {
"handlers/admin/provider/oauth/quota/antigravity.rs should import common quota helpers from shared.rs" "handlers/admin/provider/oauth/quota/antigravity.rs should import common quota helpers from shared.rs"
); );
assert!( assert!(
quota_antigravity quota_antigravity.contains("use aether_provider_pool::{")
.contains("use aether_provider_pool::build_antigravity_pool_quota_request;"), && quota_antigravity.contains("build_antigravity_pool_quota_request")
&& quota_antigravity.contains("build_antigravity_pool_quota_summary_request"),
"handlers/admin/provider/oauth/quota/antigravity.rs should delegate antigravity quota request construction to aether-provider-pool" "handlers/admin/provider/oauth/quota/antigravity.rs should delegate antigravity quota request construction to aether-provider-pool"
); );
let quota_chatgpt_web = read_workspace_file( let quota_chatgpt_web = read_workspace_file(
@@ -850,10 +850,7 @@ async fn gateway_handles_admin_global_model_routing_locally_with_trusted_admin_p
provider_catalog_repository, provider_catalog_repository,
) )
.with_global_model_repository_for_tests(global_model_repository) .with_global_model_repository_for_tests(global_model_repository)
.with_system_config_values_for_tests(vec![ .with_system_default_routing_group_for_tests(),
("scheduling_mode".to_string(), json!("fixed_order")),
("provider_priority_mode".to_string(), json!("global_key")),
]),
), ),
); );
let (gateway_url, gateway_handle) = start_server(gateway).await; let (gateway_url, gateway_handle) = start_server(gateway).await;
@@ -876,8 +873,8 @@ async fn gateway_handles_admin_global_model_routing_locally_with_trusted_admin_p
assert_eq!(payload["global_model_name"], "gpt-5"); assert_eq!(payload["global_model_name"], "gpt-5");
assert_eq!(payload["display_name"], "GPT 5"); assert_eq!(payload["display_name"], "GPT 5");
assert_eq!(payload["global_model_mappings"], json!(["gpt-5-upstream"])); assert_eq!(payload["global_model_mappings"], json!(["gpt-5-upstream"]));
assert_eq!(payload["scheduling_mode"], "fixed_order"); assert_eq!(payload["scheduling_mode"], "cache_affinity");
assert_eq!(payload["priority_mode"], "global_key"); assert_eq!(payload["priority_mode"], "provider");
assert_eq!(payload["total_providers"], 2); assert_eq!(payload["total_providers"], 2);
assert_eq!(payload["active_providers"], 2); assert_eq!(payload["active_providers"], 2);
@@ -1948,7 +1948,7 @@ async fn gateway_validates_chat_pii_redaction_system_config_locally_with_trusted
} }
#[tokio::test] #[tokio::test]
async fn gateway_handles_admin_system_provider_priority_mode_locally_with_bearer_admin_session() { async fn gateway_rejects_removed_admin_system_provider_priority_mode_with_bearer_admin_session() {
let upstream_hits = Arc::new(Mutex::new(0usize)); let upstream_hits = Arc::new(Mutex::new(0usize));
let upstream_hits_clone = Arc::clone(&upstream_hits); let upstream_hits_clone = Arc::clone(&upstream_hits);
let upstream = Router::new().route( let upstream = Router::new().route(
@@ -1962,7 +1962,7 @@ async fn gateway_handles_admin_system_provider_priority_mode_locally_with_bearer
}), }),
); );
let (upstream_url, upstream_handle) = start_server(upstream).await; let (_upstream_url, upstream_handle) = start_server(upstream).await;
let state = AppState::new().expect("gateway should build"); let state = AppState::new().expect("gateway should build");
let access_token = issue_test_admin_access_token(&state, "device-admin-config").await; let access_token = issue_test_admin_access_token(&state, "device-admin-config").await;
let gateway = build_router_with_state(state); let gateway = build_router_with_state(state);
@@ -1978,10 +1978,7 @@ async fn gateway_handles_admin_system_provider_priority_mode_locally_with_bearer
.await .await
.expect("request should succeed"); .expect("request should succeed");
assert_eq!(response.status(), StatusCode::OK); assert_eq!(response.status(), StatusCode::NOT_FOUND);
let payload: serde_json::Value = response.json().await.expect("json body should parse");
assert_eq!(payload["key"], "provider_priority_mode");
assert_eq!(payload["value"], "provider");
assert_eq!(*upstream_hits.lock().expect("mutex should lock"), 0); assert_eq!(*upstream_hits.lock().expect("mutex should lock"), 0);
gateway_handle.abort(); gateway_handle.abort();
@@ -5,6 +5,7 @@ use super::{
InMemoryVideoTaskRepository, StoredAuthApiKeySnapshot, UpsertVideoTask, VideoTaskLookupKey, InMemoryVideoTaskRepository, StoredAuthApiKeySnapshot, UpsertVideoTask, VideoTaskLookupKey,
VideoTaskReadRepository, VideoTaskStatus, VideoTaskWriteRepository, DEVELOPMENT_ENCRYPTION_KEY, VideoTaskReadRepository, VideoTaskStatus, VideoTaskWriteRepository, DEVELOPMENT_ENCRYPTION_KEY,
}; };
use crate::data::GatewayDataState;
use crate::image_capabilities::openai_image_gateway_max_generation_count; use crate::image_capabilities::openai_image_gateway_max_generation_count;
use crate::tests::{ use crate::tests::{
any, build_router_with_state, build_state_with_execution_runtime_override, json, start_server, any, build_router_with_state, build_state_with_execution_runtime_override, json, start_server,
@@ -3477,7 +3478,10 @@ async fn gateway_does_not_locally_reject_image_model_name_on_chat_completions()
let gateway = build_router_with_state( let gateway = build_router_with_state(
AppState::new() AppState::new()
.expect("gateway should build") .expect("gateway should build")
.with_auth_api_key_data_reader_for_tests(auth_repository), .with_data_state_for_tests(
GatewayDataState::with_auth_api_key_reader_for_tests(auth_repository)
.with_system_default_routing_group_for_tests(),
),
); );
let (gateway_url, gateway_handle) = start_server(gateway).await; let (gateway_url, gateway_handle) = start_server(gateway).await;
@@ -5,6 +5,7 @@ use super::{
InMemoryProviderCatalogReadRepository, InMemoryRequestCandidateRepository, InMemoryProviderCatalogReadRepository, InMemoryRequestCandidateRepository,
DEVELOPMENT_ENCRYPTION_KEY, DEVELOPMENT_ENCRYPTION_KEY,
}; };
use crate::data::GatewayDataState;
use crate::tests::{ use crate::tests::{
any, build_router, build_router_with_state, build_state_with_execution_runtime_override, json, any, build_router, build_router_with_state, build_state_with_execution_runtime_override, json,
start_server, strip_sse_keepalive_comments, AppState, Arc, Body, HeaderValue, Json, Mutex, start_server, strip_sse_keepalive_comments, AppState, Arc, Body, HeaderValue, Json, Mutex,
@@ -1301,7 +1302,10 @@ async fn gateway_returns_internal_gateway_decision_sync_fallback_with_resolved_a
let gateway = build_router_with_state( let gateway = build_router_with_state(
AppState::new() AppState::new()
.expect("gateway should build") .expect("gateway should build")
.with_auth_api_key_data_reader_for_tests(auth_repository), .with_data_state_for_tests(
GatewayDataState::with_auth_api_key_reader_for_tests(auth_repository)
.with_system_default_routing_group_for_tests(),
),
); );
let (gateway_url, gateway_handle) = start_server(gateway).await; let (gateway_url, gateway_handle) = start_server(gateway).await;
+22 -3
View File
@@ -18,6 +18,10 @@ use aether_data::repository::provider_catalog::InMemoryProviderCatalogReadReposi
use aether_data_contracts::repository::provider_catalog::{ use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider, StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
}; };
use aether_scheduler_core::{
build_scheduler_affinity_cache_key_for_api_key_id_with_client_session_and_scope,
SchedulerAffinityScope,
};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
fn hash_api_key(value: &str) -> String { fn hash_api_key(value: &str) -> String {
@@ -26,6 +30,18 @@ fn hash_api_key(value: &str) -> String {
format!("{:x}", hasher.finalize()) format!("{:x}", hasher.finalize())
} }
fn system_default_affinity_cache_key(api_key_id: &str, api_format: &str, model: &str) -> String {
let scope = SchedulerAffinityScope::new("system-default", Some(1));
build_scheduler_affinity_cache_key_for_api_key_id_with_client_session_and_scope(
api_key_id,
api_format,
model,
None,
Some(&scope),
)
.expect("system-default affinity cache key should build")
}
fn sample_auth_snapshot( fn sample_auth_snapshot(
api_key_id: &str, api_key_id: &str,
user_id: &str, user_id: &str,
@@ -626,6 +642,7 @@ async fn gateway_forwards_public_request_to_remote_tunnel_owner_before_fallback_
"development-key", "development-key",
) )
.with_auth_api_key_reader(auth_repository) .with_auth_api_key_reader(auth_repository)
.with_system_default_routing_group_for_tests()
.with_system_config_values_for_tests(vec![( .with_system_config_values_for_tests(vec![(
tunnel_attachment_key("node-owner"), tunnel_attachment_key("node-owner"),
serde_json::to_value(crate::tunnel::TunnelAttachmentRecord { serde_json::to_value(crate::tunnel::TunnelAttachmentRecord {
@@ -648,7 +665,7 @@ async fn gateway_forwards_public_request_to_remote_tunnel_owner_before_fallback_
state.client = short_timeout_client.clone(); state.client = short_timeout_client.clone();
state.owner_forward_client = short_timeout_client; state.owner_forward_client = short_timeout_client;
state.remember_scheduler_affinity_target( state.remember_scheduler_affinity_target(
"scheduler_affinity:api-key-affinity-1:openai:chat:gpt-4.1", &system_default_affinity_cache_key("api-key-affinity-1", "openai:chat", "gpt-4.1"),
crate::cache::SchedulerAffinityTarget { crate::cache::SchedulerAffinityTarget {
provider_id: "provider-owner".to_string(), provider_id: "provider-owner".to_string(),
endpoint_id: "endpoint-owner".to_string(), endpoint_id: "endpoint-owner".to_string(),
@@ -853,6 +870,7 @@ async fn gateway_aggregates_sync_sse_from_remote_tunnel_owner_before_returning_t
"development-key", "development-key",
) )
.with_auth_api_key_reader(auth_repository) .with_auth_api_key_reader(auth_repository)
.with_system_default_routing_group_for_tests()
.with_system_config_values_for_tests(vec![( .with_system_config_values_for_tests(vec![(
tunnel_attachment_key("node-cli-owner"), tunnel_attachment_key("node-cli-owner"),
serde_json::to_value(crate::tunnel::TunnelAttachmentRecord { serde_json::to_value(crate::tunnel::TunnelAttachmentRecord {
@@ -869,7 +887,7 @@ async fn gateway_aggregates_sync_sse_from_remote_tunnel_owner_before_returning_t
.with_data_state_for_tests(data_state) .with_data_state_for_tests(data_state)
.with_tunnel_identity_for_tests("gateway-a", Some("http://gateway-a:8080")); .with_tunnel_identity_for_tests("gateway-a", Some("http://gateway-a:8080"));
state.remember_scheduler_affinity_target( state.remember_scheduler_affinity_target(
"scheduler_affinity:api-key-affinity-cli-1:openai:responses:gpt-5.4", &system_default_affinity_cache_key("api-key-affinity-cli-1", "openai:responses", "gpt-5.4"),
crate::cache::SchedulerAffinityTarget { crate::cache::SchedulerAffinityTarget {
provider_id: "provider-cli-owner".to_string(), provider_id: "provider-cli-owner".to_string(),
endpoint_id: "endpoint-cli-owner".to_string(), endpoint_id: "endpoint-cli-owner".to_string(),
@@ -1100,6 +1118,7 @@ async fn gateway_streamifies_sync_json_from_remote_tunnel_owner_before_returning
"development-key", "development-key",
) )
.with_auth_api_key_reader(auth_repository) .with_auth_api_key_reader(auth_repository)
.with_system_default_routing_group_for_tests()
.with_system_config_values_for_tests(vec![( .with_system_config_values_for_tests(vec![(
tunnel_attachment_key("node-cli-owner"), tunnel_attachment_key("node-cli-owner"),
serde_json::to_value(crate::tunnel::TunnelAttachmentRecord { serde_json::to_value(crate::tunnel::TunnelAttachmentRecord {
@@ -1120,7 +1139,7 @@ async fn gateway_streamifies_sync_json_from_remote_tunnel_owner_before_returning
.build() .build()
.expect("short shared client should build"); .expect("short shared client should build");
state.remember_scheduler_affinity_target( state.remember_scheduler_affinity_target(
"scheduler_affinity:api-key-affinity-cli-1:openai:responses:gpt-5.4", &system_default_affinity_cache_key("api-key-affinity-cli-1", "openai:responses", "gpt-5.4"),
crate::cache::SchedulerAffinityTarget { crate::cache::SchedulerAffinityTarget {
provider_id: "provider-cli-owner".to_string(), provider_id: "provider-cli-owner".to_string(),
endpoint_id: "endpoint-cli-owner".to_string(), endpoint_id: "endpoint-cli-owner".to_string(),