mod common; use axum::http::StatusCode; use common::*; // ═══════════════════════════════════════════════════════════════════ // OTA check // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn prompt_ota_check() { let (app, _pool) = build_test_app().await; let token = register_token(&app, "otacheck").await; let (status, body) = send( &app, post( "/api/v1/prompts/check", &token, serde_json::json!({ "device_id": "test-device-001", "versions": { "reflection": 0, "compaction": 0, "extraction": 0 } }), ), ).await; assert_eq!(status, StatusCode::OK); assert!(body["updates"].is_array()); assert!(body["server_time"].is_string()); // 3 builtin templates should have updates assert_eq!(body["updates"].as_array().unwrap().len(), 3); } // ═══════════════════════════════════════════════════════════════════ // Prompt list (admin only) // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn prompt_list_requires_permission() { let (app, _pool) = build_test_app().await; let token = register_token(&app, "promptuser").await; let (status, _) = send(&app, get("/api/v1/prompts", &token)).await; // Regular user has prompt:read via user role → may succeed or fail based on permissions // User role has prompt:read → should succeed assert_eq!(status, StatusCode::OK); } #[tokio::test] async fn prompt_list_shows_builtins() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "promptlist").await; let (status, body) = send(&app, get("/api/v1/prompts", &admin)).await; assert_eq!(status, StatusCode::OK); let items = body["items"].as_array().unwrap_or_else(|| { // Fallback: some handlers may return bare array body.as_array().unwrap() }); assert!(items.len() >= 3, "should have 3 builtin templates, got {}: {body}", items.len()); } // ═══════════════════════════════════════════════════════════════════ // Prompt CRUD // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn prompt_create_and_get() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "promptcreate").await; // Create let (status, body) = send( &app, post( "/api/v1/prompts", &admin, serde_json::json!({ "name": "test-prompt", "category": "test", "description": "A test prompt", "system_prompt": "You are a test assistant.", "user_prompt_template": "Hello {{name}}", "variables": [{ "name": "name", "required": true }] }), ), ).await; assert_eq!(status, StatusCode::OK, "create prompt: {body}"); // Get by name let (status, body) = send(&app, get("/api/v1/prompts/test-prompt", &admin)).await; assert_eq!(status, StatusCode::OK); assert_eq!(body["name"], "test-prompt"); // Update metadata let (status, body) = send( &app, put( "/api/v1/prompts/test-prompt", &admin, serde_json::json!({ "description": "Updated description" }), ), ).await; assert_eq!(status, StatusCode::OK); assert_eq!(body["description"], "Updated description"); } // ═══════════════════════════════════════════════════════════════════ // Prompt versions // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn prompt_version_publish_and_list() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "promptver").await; // Create template first send( &app, post( "/api/v1/prompts", &admin, serde_json::json!({ "name": "versioned-prompt", "category": "test", "system_prompt": "Version 1 system prompt" }), ), ).await; // Publish a new version let (status, body) = send( &app, post( "/api/v1/prompts/versioned-prompt/versions", &admin, serde_json::json!({ "system_prompt": "Version 2 system prompt", "changelog": "Updated for testing" }), ), ).await; assert_eq!(status, StatusCode::OK, "publish version: {body}"); // List versions let (status, body) = send(&app, get("/api/v1/prompts/versioned-prompt/versions", &admin)).await; assert_eq!(status, StatusCode::OK); assert!(body.is_array()); assert!(body.as_array().unwrap().len() >= 2); } // ═══════════════════════════════════════════════════════════════════ // Prompt archive // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn prompt_archive() { let (app, pool) = build_test_app().await; let sa = super_admin_token(&app, &pool, "promptarchive").await; // Create send( &app, post( "/api/v1/prompts", &sa, serde_json::json!({ "name": "to-archive", "category": "test", "system_prompt": "Will be archived" }), ), ).await; // Archive (delete) let (status, _) = send(&app, delete("/api/v1/prompts/to-archive", &sa)).await; assert_eq!(status, StatusCode::OK); }