From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 083841FF09B for ; Mon, 17 Aug 2026 14:58:09 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id C52FD2179E; Mon, 17 Aug 2026 14:57:55 +0200 (CEST) From: Lukas Wagner To: pdm-devel@lists.proxmox.com Subject: [PATCH datacenter-manager 15/20] tests: add example tests for SDN API routes Date: Mon, 17 Aug 2026 14:57:22 +0200 Message-ID: <20260817125727.454039-16-l.wagner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260817125727.454039-1-l.wagner@proxmox.com> References: <20260817125727.454039-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: 1786971436929 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.888 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: IKCJCM3WEFGYQFFLN7OZKSYXCGYLFTTK X-Message-ID-Hash: IKCJCM3WEFGYQFFLN7OZKSYXCGYLFTTK 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 | 88 +++++++++++++++++++ 6 files changed, 121 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 1d72114e..550d75f7 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..6eb03101 --- /dev/null +++ b/server/tests/test_sdn.rs @@ -0,0 +1,88 @@ +use proxmox_router::State; +use pve_api_types::{ClusterNodeIndexResponse, 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(), State(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(), State(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