Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Fix usage_stats SQL: add ::timestamptz cast for Option<String> params - Fix usage_stats SQL: add ::bigint cast for COALESCE(SUM(...)) - Fix telemetry INSERT: add ::timestamptz cast for reported_at column - Fix config_analysis_empty test: seed data makes total_items > 0 - Fix key_pool_crud test: key_value must be >= 20 chars - Fix SkillManifest test helpers: add missing tools field All 1048 tests pass: 580 Rust + 138 SaaS + 330 Desktop Vitest
235 lines
8.6 KiB
Rust
235 lines
8.6 KiB
Rust
mod common;
|
|
|
|
use axum::http::StatusCode;
|
|
use common::*;
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Provider CRUD
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn provider_crud_full_lifecycle() {
|
|
let (app, pool) = build_test_app().await;
|
|
let admin = admin_token(&app, &pool, "provadmin").await;
|
|
|
|
// Create
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/providers",
|
|
&admin,
|
|
serde_json::json!({
|
|
"name": "test-provider",
|
|
"display_name": "Test Provider",
|
|
"base_url": "https://api.example.com/v1"
|
|
}),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::CREATED, "create provider failed: {body}");
|
|
let provider_id = body["id"].as_str().unwrap().to_string();
|
|
|
|
// List (paginated)
|
|
let (status, body) = send(&app, get("/api/v1/providers", &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
let items = body["items"].as_array().expect("providers should be paginated {items}");
|
|
assert!(items.iter().any(|p| p["id"] == provider_id));
|
|
|
|
// Get
|
|
let (status, body) = send(&app, get(&format!("/api/v1/providers/{provider_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["name"], "test-provider");
|
|
|
|
// Update
|
|
let (status, body) = send(
|
|
&app,
|
|
patch(
|
|
&format!("/api/v1/providers/{provider_id}"),
|
|
&admin,
|
|
serde_json::json!({ "display_name": "Updated Provider" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["display_name"], "Updated Provider");
|
|
|
|
// Delete
|
|
let (status, _) = send(&app, delete(&format!("/api/v1/providers/{provider_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
|
|
// Verify deleted
|
|
let (status, _) = send(&app, get(&format!("/api/v1/providers/{provider_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn provider_create_forbidden_for_user() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "provuser").await;
|
|
let (status, _) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/providers",
|
|
&token,
|
|
serde_json::json!({ "name": "x", "display_name": "X", "base_url": "https://x.com" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn provider_list_accessible_to_all_authenticated() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "listprovuser").await;
|
|
let (status, body) = send(&app, get("/api/v1/providers", &token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert!(body["items"].is_array(), "providers list should be paginated: {body}");
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Model CRUD
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn model_crud_with_provider() {
|
|
let (app, pool) = build_test_app().await;
|
|
let admin = admin_token(&app, &pool, "modeladmin").await;
|
|
|
|
// Create provider first
|
|
let (_, prov_body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/providers",
|
|
&admin,
|
|
serde_json::json!({ "name": "model-prov", "display_name": "Model Prov", "base_url": "https://api.test.com/v1" }),
|
|
),
|
|
).await;
|
|
let provider_id = prov_body["id"].as_str().unwrap();
|
|
|
|
// Create model
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/models",
|
|
&admin,
|
|
serde_json::json!({
|
|
"provider_id": provider_id,
|
|
"model_id": "test-model-v1",
|
|
"alias": "Test Model",
|
|
"context_window": 8192
|
|
}),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::CREATED, "create model: {body}");
|
|
let model_id = body["id"].as_str().unwrap();
|
|
|
|
// List models (paginated)
|
|
let (status, list) = send(&app, get("/api/v1/models", &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert!(list["items"].is_array(), "models list should be paginated: {list}");
|
|
|
|
// Get model
|
|
let (status, _) = send(&app, get(&format!("/api/v1/models/{model_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
|
|
// Update model
|
|
let (status, body) = send(
|
|
&app,
|
|
patch(
|
|
&format!("/api/v1/models/{model_id}"),
|
|
&admin,
|
|
serde_json::json!({ "alias": "Updated Alias" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["alias"], "Updated Alias");
|
|
|
|
// Delete model
|
|
let (status, _) = send(&app, delete(&format!("/api/v1/models/{model_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn model_create_forbidden_for_user() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "modeluser").await;
|
|
let (status, _) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/models",
|
|
&token,
|
|
serde_json::json!({ "provider_id": "x", "model_id": "y", "alias": "Z" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Account API Key
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn api_key_requires_existing_provider() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "keyuser").await;
|
|
let (status, _) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/keys",
|
|
&token,
|
|
serde_json::json!({ "provider_id": "nonexistent", "key_value": "sk-test", "key_label": "Test" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn api_key_lifecycle_with_provider() {
|
|
let (app, pool) = build_test_app().await;
|
|
let admin = admin_token(&app, &pool, "keyadmin").await;
|
|
|
|
// Create provider
|
|
let (_, prov) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/providers",
|
|
&admin,
|
|
serde_json::json!({ "name": "key-prov", "display_name": "Key Prov", "base_url": "https://api.test.com/v1" }),
|
|
),
|
|
).await;
|
|
let provider_id = prov["id"].as_str().unwrap();
|
|
|
|
// Create key as regular user
|
|
let user_token = register_token(&app, "keyowner").await;
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/keys",
|
|
&user_token,
|
|
serde_json::json!({ "provider_id": provider_id, "key_value": "sk-test-key-123", "key_label": "My Key" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::CREATED, "create key: {body}");
|
|
let key_id = body["id"].as_str().unwrap();
|
|
|
|
// List keys (paginated)
|
|
let (status, list) = send(&app, get("/api/v1/keys", &user_token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert!(list["items"].is_array(), "keys list should be paginated: {list}");
|
|
|
|
// Delete key
|
|
let (status, _) = send(&app, delete(&format!("/api/v1/keys/{key_id}"), &user_token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Usage stats
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn usage_stats_empty() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "usageuser").await;
|
|
let (status, body) = send(&app, get("/api/v1/usage", &token)).await;
|
|
assert_eq!(status, StatusCode::OK, "usage stats response: {body}");
|
|
assert_eq!(body["total_requests"], 0);
|
|
}
|