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
176 lines
7.6 KiB
Rust
176 lines
7.6 KiB
Rust
mod common;
|
|
|
|
use axum::http::StatusCode;
|
|
use common::*;
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config analysis
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_analysis_empty() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "cfganalyze").await;
|
|
let (status, body) = send(&app, get("/api/v1/config/analysis", &token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
// init_db seeds 24 default config items, so total_items > 0 is expected
|
|
assert!(body["total_items"].as_i64().unwrap_or(-1) >= 0, "total_items should be non-negative");
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config items CRUD
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_items_crud() {
|
|
let (app, pool) = build_test_app().await;
|
|
let admin = admin_token(&app, &pool, "cfgadmin").await;
|
|
|
|
// Create config item
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/config/items",
|
|
&admin,
|
|
serde_json::json!({
|
|
"category": "server",
|
|
"key_path": "server.host",
|
|
"value_type": "string",
|
|
"current_value": "0.0.0.0",
|
|
"description": "Server bind address"
|
|
}),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::CREATED, "create config item: {body}");
|
|
let item_id = body["id"].as_str().unwrap();
|
|
|
|
// List
|
|
let (status, list) = send(&app, get("/api/v1/config/items", &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert!(list.is_array() || list["items"].is_array());
|
|
|
|
// Get
|
|
let (status, body) = send(&app, get(&format!("/api/v1/config/items/{item_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["key_path"], "server.host");
|
|
|
|
// Update
|
|
let (status, body) = send(
|
|
&app,
|
|
put(
|
|
&format!("/api/v1/config/items/{item_id}"),
|
|
&admin,
|
|
serde_json::json!({ "current_value": "127.0.0.1" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["current_value"], "127.0.0.1");
|
|
|
|
// Delete
|
|
let (status, _) = send(&app, delete(&format!("/api/v1/config/items/{item_id}"), &admin)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn config_items_write_forbidden_for_user() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "cfguser").await;
|
|
let (status, _) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/config/items",
|
|
&token,
|
|
serde_json::json!({ "category": "x", "key_path": "y", "value_type": "string" }),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config seed
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_seed_admin_only() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let user_token = register_token(&app, "cfgseeduser").await;
|
|
let (status, _) = send(&app, post("/api/v1/config/seed", &user_token, serde_json::json!({}))).await;
|
|
assert_eq!(status, StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config sync (push)
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_sync_push() {
|
|
let (app, pool) = build_test_app().await;
|
|
let admin = admin_token(&app, &pool, "cfgsync").await;
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/config/sync",
|
|
&admin,
|
|
serde_json::json!({
|
|
"client_fingerprint": "test-desktop-v1",
|
|
"action": "push",
|
|
"config_keys": ["server.host", "server.port"],
|
|
"client_values": { "server.host": "192.168.1.1", "server.port": "9090" }
|
|
}),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::OK, "config sync push: {body}");
|
|
// Push mode: keys don't exist in SaaS → auto-created
|
|
assert_eq!(body["created"], 2);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config diff
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_diff() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "cfgdiff").await;
|
|
let (status, body) = send(
|
|
&app,
|
|
post(
|
|
"/api/v1/config/diff",
|
|
&token,
|
|
serde_json::json!({
|
|
"client_fingerprint": "test-client",
|
|
"action": "push",
|
|
"config_keys": ["server.host"],
|
|
"client_values": { "server.host": "0.0.0.0" }
|
|
}),
|
|
),
|
|
).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
assert_eq!(body["total_keys"], 1);
|
|
assert!(body["items"].is_array());
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config sync logs
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_sync_logs() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "cfglogs").await;
|
|
let (status, _) = send(&app, get("/api/v1/config/sync-logs", &token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// Config pull
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
#[tokio::test]
|
|
async fn config_pull_empty() {
|
|
let (app, _pool) = build_test_app().await;
|
|
let token = register_token(&app, "cfgpull").await;
|
|
let (status, _) = send(&app, get("/api/v1/config/pull", &token)).await;
|
|
assert_eq!(status, StatusCode::OK);
|
|
}
|