From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 63BBC1FF0E1 for ; Thu, 27 Aug 2026 13:43:35 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 293B421628; Thu, 27 Aug 2026 13:43:15 +0200 (CEST) From: Lukas Wagner To: pdm-devel@lists.proxmox.com Subject: [PATCH datacenter-manager v3 16/21] tests: add example tests for SDN API routes Date: Thu, 27 Aug 2026 13:42:39 +0200 Message-ID: <20260827114244.424784-17-l.wagner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260827114244.424784-1-l.wagner@proxmox.com> References: <20260827114244.424784-1-l.wagner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1787830961609 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.591 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: PP6LHGHJ2DB6UUQMZECPN3LIR6SDO4VZ X-Message-ID-Hash: PP6LHGHJ2DB6UUQMZECPN3LIR6SDO4VZ X-MailFrom: l.wagner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Using the previously added dependency-injected abstractions for accessing remotes and clients, and by using the test helpers, we can now fairly trivially create test cases that call the API handler directly. These tests also demonstrate how previously captured API responses from real PVE nodes can be used to build test cases. Signed-off-by: Lukas Wagner --- server/src/api/sdn/vnets.rs | 2 +- .../pve/remote-a/list_vnets.json | 8 ++ .../pve/remote-a/list_zones.json | 8 ++ .../pve/remote-b/list_vnets.json | 8 ++ .../pve/remote-b/list_zones.json | 8 ++ server/tests/test_sdn.rs | 86 +++++++++++++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 server/tests/api_responses/pve/remote-a/list_vnets.json create mode 100644 server/tests/api_responses/pve/remote-a/list_zones.json create mode 100644 server/tests/api_responses/pve/remote-b/list_vnets.json create mode 100644 server/tests/api_responses/pve/remote-b/list_zones.json create mode 100644 server/tests/test_sdn.rs diff --git a/server/src/api/sdn/vnets.rs b/server/src/api/sdn/vnets.rs index 312d46b6..e42fcab7 100644 --- a/server/src/api/sdn/vnets.rs +++ b/server/src/api/sdn/vnets.rs @@ -59,7 +59,7 @@ pub const ROUTER: Router = Router::new() } )] /// Query VNets of PVE remotes with optional filtering options -async fn list_vnets( +pub async fn list_vnets( pending: Option, running: Option, remotes: Option>, diff --git a/server/tests/api_responses/pve/remote-a/list_vnets.json b/server/tests/api_responses/pve/remote-a/list_vnets.json new file mode 100644 index 00000000..a105de13 --- /dev/null +++ b/server/tests/api_responses/pve/remote-a/list_vnets.json @@ -0,0 +1,8 @@ +[ + { + "digest" : "3458032372eb62efb730fec12b34d36627a9e6e8", + "type" : "vnet", + "vnet" : "aaaavnet", + "zone" : "aaaa" + } +] diff --git a/server/tests/api_responses/pve/remote-a/list_zones.json b/server/tests/api_responses/pve/remote-a/list_zones.json new file mode 100644 index 00000000..f7932bd9 --- /dev/null +++ b/server/tests/api_responses/pve/remote-a/list_zones.json @@ -0,0 +1,8 @@ +[ + { + "digest" : "142f8be078a0fb61fa28a89cffdb17f64b05e3f9", + "ipam" : "pve", + "type" : "simple", + "zone" : "aaaa" + } +] diff --git a/server/tests/api_responses/pve/remote-b/list_vnets.json b/server/tests/api_responses/pve/remote-b/list_vnets.json new file mode 100644 index 00000000..4a59edc7 --- /dev/null +++ b/server/tests/api_responses/pve/remote-b/list_vnets.json @@ -0,0 +1,8 @@ +[ + { + "digest" : "56e0d24671dca1e6cc30a2cfdfab79a037e66a44", + "type" : "vnet", + "vnet" : "bbbbvnet", + "zone" : "bbbb" + } +] diff --git a/server/tests/api_responses/pve/remote-b/list_zones.json b/server/tests/api_responses/pve/remote-b/list_zones.json new file mode 100644 index 00000000..75fd763a --- /dev/null +++ b/server/tests/api_responses/pve/remote-b/list_zones.json @@ -0,0 +1,8 @@ +[ + { + "digest" : "bd994284b5d766ab58b5cb69f7363153d42816f7", + "ipam" : "pve", + "type" : "simple", + "zone" : "bbbb" + } +] diff --git a/server/tests/test_sdn.rs b/server/tests/test_sdn.rs new file mode 100644 index 00000000..204a94cd --- /dev/null +++ b/server/tests/test_sdn.rs @@ -0,0 +1,86 @@ +use pve_api_types::{ListZonesType, SdnVnet, SdnVnetType, SdnZone}; +use server::context::ContextFactory; + +use crate::common::{TestApplication, rpcenv}; + +pub mod common; + +common::test_pve_client!(SdnPveClient { + async fn list_zones( + &self, + _pending: Option, + _running: Option, + _ty: Option, + ) -> Result, proxmox_client::Error> { + common::read_captured_response(&format!( + "tests/api_responses/pve/{}/list_zones.json", + self.remote(), + )).await + } + + async fn list_vnets( + &self, + _pending: Option, + _running: Option, + ) -> Result, proxmox_client::Error> { + common::read_captured_response(&format!( + "tests/api_responses/pve/{}/list_vnets.json", + self.remote(), + )).await + } +}); + +#[tokio::test] +async fn test_lists_zones() { + common::test_setup(); + + let test_app = TestApplication::new() + .with_pve_remote("remote-a", Default::default(), SdnPveClient) + .with_pve_remote("remote-b", Default::default(), SdnPveClient); + + let app = test_app.make_pdm_application().unwrap(); + + let mut result = + server::api::sdn::zones::list_zones(None, None, None, None, &mut rpcenv(), app) + .await + .unwrap(); + + // We don't guarantee any ordering + result.sort_by(|a, b| a.remote.cmp(&b.remote)); + + assert_eq!(result.len(), 2); + + assert_eq!(result[0].remote, "remote-a"); + assert_eq!(result[0].zone.zone, "aaaa"); + assert_eq!(result[0].zone.ty, ListZonesType::Simple); + assert_eq!(result[1].remote, "remote-b"); + assert_eq!(result[1].zone.zone, "bbbb"); + assert_eq!(result[1].zone.ty, ListZonesType::Simple); +} + +#[tokio::test] +async fn test_lists_vnets() { + common::test_setup(); + + let test_app = TestApplication::new() + .with_pve_remote("remote-a", Default::default(), SdnPveClient) + .with_pve_remote("remote-b", Default::default(), SdnPveClient); + + let app = test_app.make_pdm_application().unwrap(); + + let mut result = server::api::sdn::vnets::list_vnets(None, None, None, &mut rpcenv(), app) + .await + .unwrap(); + + // We don't guarantee any ordering + result.sort_by(|a, b| a.remote.cmp(&b.remote)); + + assert_eq!(result.len(), 2); + + assert_eq!(result[0].remote, "remote-a"); + assert_eq!(result[0].vnet.vnet, "aaaavnet"); + assert_eq!(result[0].vnet.ty, SdnVnetType::Vnet); + assert_eq!(result[1].remote, "remote-b"); + assert_eq!(result[1].vnet.vnet, "bbbbvnet"); + assert_eq!(result[1].vnet.ty, SdnVnetType::Vnet); +} -- 2.47.3