use anyhow::Result; use axum::http::StatusCode; use serde_json::json; use uuid::Uuid; use crate::common::TestApp; #[tokio::test] async fn test_update_dashboard_endpoint() -> Result<()> { // Setup test app let app = TestApp::new().await?; // Create a test dashboard first let create_response = app .client .post("/api/v1/dashboards") .bearer_auth(&app.test_user.token) .json(&json!({ "name": "Test Dashboard", "description": "Test Description", "file": "name: Test Dashboard\ndescription: Test Description\nrows: []" })) .send() .await?; let create_body: serde_json::Value = create_response.json().await?; let dashboard_id = create_body["dashboard"]["id"].as_str().unwrap(); // Make request to update dashboard let update_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .json(&json!({ "name": "Updated Dashboard Name", "description": "Updated description" })) .send() .await?; // Verify response assert_eq!(update_response.status(), StatusCode::OK); // Parse response body let update_body: serde_json::Value = update_response.json().await?; // Verify dashboard properties assert_eq!(update_body["dashboard"]["name"], "Updated Dashboard Name"); assert_eq!(update_body["dashboard"]["description"], "Updated description"); Ok(()) } #[tokio::test] async fn test_update_dashboard_with_file_endpoint() -> Result<()> { // Setup test app let app = TestApp::new().await?; // Create a test dashboard first let create_response = app .client .post("/api/v1/dashboards") .bearer_auth(&app.test_user.token) .json(&json!({ "name": "Test Dashboard", "description": "Test Description", "file": "name: Test Dashboard\ndescription: Test Description\nrows: []" })) .send() .await?; let create_body: serde_json::Value = create_response.json().await?; let dashboard_id = create_body["dashboard"]["id"].as_str().unwrap(); // YAML content for update let yaml_content = r#" name: File Updated Dashboard description: Updated from file rows: [] "#; // Make request to update dashboard with file let update_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .json(&json!({ "file": yaml_content })) .send() .await?; // Verify response assert_eq!(update_response.status(), StatusCode::OK); // Parse response body let update_body: serde_json::Value = update_response.json().await?; // Verify dashboard properties assert_eq!(update_body["dashboard"]["name"], "File Updated Dashboard"); assert_eq!(update_body["dashboard"]["description"], "Updated from file"); Ok(()) } #[tokio::test] async fn test_restore_dashboard_version() -> Result<()> { // Setup test app let app = TestApp::new().await?; // 1. Create a dashboard with initial content (version 1) let v1_yaml_content = r#" name: Original Dashboard description: Original description rows: - items: - id: "00000000-0000-0000-0000-000000000001" row_height: 300 column_sizes: [12] id: 1 "#; let create_response = app .client .post("/api/v1/dashboards") .bearer_auth(&app.test_user.token) .json(&json!({ "file": v1_yaml_content })) .send() .await?; let create_body: serde_json::Value = create_response.json().await?; let dashboard_id = create_body["dashboard"]["id"].as_str().unwrap(); assert_eq!(create_body["dashboard"]["version"], 1); // 2. Update to create version 2 with different content let v2_yaml_content = r#" name: Updated Dashboard description: Updated description rows: - items: - id: "00000000-0000-0000-0000-000000000001" - id: "00000000-0000-0000-0000-000000000002" row_height: 400 column_sizes: [6, 6] id: 1 - items: - id: "00000000-0000-0000-0000-000000000003" row_height: 300 column_sizes: [12] id: 2 "#; let update_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .json(&json!({ "file": v2_yaml_content })) .send() .await?; let update_body: serde_json::Value = update_response.json().await?; assert_eq!(update_body["dashboard"]["version"], 2); assert_eq!(update_body["dashboard"]["name"], "Updated Dashboard"); // 3. Restore to version 1 let restore_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .json(&json!({ "restore_to_version": 1, // Also add other fields to verify they're ignored "name": "This Name Should Be Ignored", "description": "This Description Should Be Ignored" })) .send() .await?; // Verify response assert_eq!(restore_response.status(), StatusCode::OK); // Parse response body let restore_body: serde_json::Value = restore_response.json().await?; // 4. Verify a new version (3) is created with content from version 1 assert_eq!(restore_body["dashboard"]["version"], 3); assert_eq!(restore_body["dashboard"]["name"], "Original Dashboard"); assert_eq!(restore_body["dashboard"]["description"], "Original description"); // 5. Verify by fetching the dashboard again let get_response = app .client .get(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .send() .await?; assert_eq!(get_response.status(), StatusCode::OK); let fetched_dashboard: serde_json::Value = get_response.json().await?; // Verify the fetched dashboard matches the restored version assert_eq!(fetched_dashboard["dashboard"]["name"], "Original Dashboard"); assert_eq!(fetched_dashboard["dashboard"]["version"], 3); Ok(()) } #[tokio::test] async fn test_restore_nonexistent_version() -> Result<()> { // Setup test app let app = TestApp::new().await?; // 1. Create a dashboard let create_response = app .client .post("/api/v1/dashboards") .bearer_auth(&app.test_user.token) .json(&json!({ "name": "Test Dashboard", "description": "Test Description", "file": "name: Test Dashboard\ndescription: Test Description\nrows: []" })) .send() .await?; let create_body: serde_json::Value = create_response.json().await?; let dashboard_id = create_body["dashboard"]["id"].as_str().unwrap(); // 2. Attempt to restore to a non-existent version (999) let restore_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth(&app.test_user.token) .json(&json!({ "restore_to_version": 999 })) .send() .await?; // 3. Verify the request fails with an appropriate status code assert_eq!(restore_response.status(), StatusCode::BAD_REQUEST); // 4. Verify error message contains information about the version not being found let error_body: serde_json::Value = restore_response.json().await?; let error_message = error_body["error"].as_str().unwrap_or(""); assert!(error_message.contains("Version") && error_message.contains("not found"), "Error message does not indicate version not found issue: {}", error_message); Ok(()) } #[tokio::test] async fn test_permission_checks_for_restoration() -> Result<()> { // Setup test app let app = TestApp::new().await?; // 1. Create a dashboard as first user let create_response = app .client .post("/api/v1/dashboards") .bearer_auth(&app.test_user.token) .json(&json!({ "name": "Test Dashboard", "description": "Test Description", "file": "name: Test Dashboard\ndescription: Test Description\nrows: []" })) .send() .await?; let create_body: serde_json::Value = create_response.json().await?; let dashboard_id = create_body["dashboard"]["id"].as_str().unwrap(); // 2. Create a second user with no access to the dashboard // Note: In a real test, you would create a second user and ensure they don't have access // We'll simulate an unauthorized access attempt directly // 3. Attempt to restore as unauthorized user let restore_response = app .client .put(&format!("/api/v1/dashboards/{}", dashboard_id)) .bearer_auth("invalid-token") // Using invalid token to simulate unauthorized access .json(&json!({ "restore_to_version": 1 })) .send() .await?; // 4. Verify the request fails with a 401 Unauthorized or 403 Forbidden assert!(restore_response.status() == StatusCode::UNAUTHORIZED || restore_response.status() == StatusCode::FORBIDDEN); Ok(()) }