//! WP-10: /api/system/inventory mod common; use axum::http::StatusCode; use common::{get, post, test_app_with_admin}; use serde_json::json; const ADMIN: &str = "admin@example.com"; const PW: &str = "admin-password-123"; #[tokio::test] async fn inventory_is_empty_until_refreshed_and_then_lists_packages() { let app = test_app_with_admin().await; let token = common::login(&app, ADMIN, PW).await.access; let res = get(&app, "/api/system/inventory", Some(&token)).await; assert_eq!(res.status, StatusCode::OK); assert!(res.json["refreshed_at"].is_null()); assert_eq!(res.json["packages"].as_array().unwrap().len(), 0); let run = post( &app, "/api/jobs/run", json!({"kind": "package_refresh"}), Some(&token), ) .await; assert_eq!(run.status, StatusCode::ACCEPTED); for _ in 0..50 { let r = get( &app, &format!("/api/jobs/{}", run.json["id"].as_str().unwrap()), Some(&token), ) .await; if r.json["status"] != "running" { assert_eq!(r.json["status"], "success", "{}", r.json["log"]); break; } tokio::time::sleep(std::time::Duration::from_millis(20)).await; } let res = get(&app, "/api/system/inventory", Some(&token)).await; assert!(res.json["refreshed_at"].is_string()); assert_eq!(res.json["os"]["hostname"], "fake-host"); assert_eq!(res.json["os"]["reboot_required"], true); let pkgs = res.json["packages"].as_array().unwrap(); assert!(pkgs.len() >= 5); let openssl = pkgs.iter().find(|p| p["name"] == "openssl").unwrap(); assert_eq!(openssl["candidate"], "3.0.16-1~deb12u1"); assert_eq!(openssl["is_security"], true); assert_eq!(res.json["summary"]["upgradable"], 3); assert_eq!(res.json["summary"]["security"], 2); assert_eq!( get(&app, "/api/system/inventory", None).await.status, StatusCode::UNAUTHORIZED ); }