From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 25C361FF13C for ; Thu, 02 Apr 2026 00:53:01 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A7B4A2A6F; Thu, 2 Apr 2026 00:53:29 +0200 (CEST) From: Thomas Lamprecht To: pbs-devel@lists.proxmox.com Subject: [PATCH v3 1/5] client: repository: add tests for BackupRepository parsing Date: Thu, 2 Apr 2026 00:48:57 +0200 Message-ID: <20260401225305.4069441-2-t.lamprecht@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260401225305.4069441-1-t.lamprecht@proxmox.com> References: <20260401225305.4069441-1-t.lamprecht@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1775083947817 X-SPAM-LEVEL: Spam detection results: 0 AWL -1.500 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. 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: 66ES3ID72U77VS3MDTPIHDWEIB3KXYYY X-Message-ID-Hash: 66ES3ID72U77VS3MDTPIHDWEIB3KXYYY X-MailFrom: t.lamprecht@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 Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add tests for the existing FromStr, Display, and new() implementations of BackupRepository, covering URL parsing with various combinations of user, host, port, datastore, IPv4, IPv6, and API tokens, as well as the IPv6 bracket-wrapping behavior in the constructor. Signed-off-by: Thomas Lamprecht --- no changes since v2. pbs-client/src/backup_repo.rs | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/pbs-client/src/backup_repo.rs b/pbs-client/src/backup_repo.rs index 458f89dc2..45c859d67 100644 --- a/pbs-client/src/backup_repo.rs +++ b/pbs-client/src/backup_repo.rs @@ -115,3 +115,82 @@ impl std::str::FromStr for BackupRepository { }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_datastore_only() { + let repo: BackupRepository = "mystore".parse().unwrap(); + assert_eq!(repo.store(), "mystore"); + assert_eq!(repo.host(), "localhost"); + assert_eq!(repo.port(), 8007); + assert_eq!(repo.auth_id().to_string(), "root@pam"); + } + + #[test] + fn parse_host_and_datastore() { + let repo: BackupRepository = "myhost:mystore".parse().unwrap(); + assert_eq!(repo.host(), "myhost"); + assert_eq!(repo.store(), "mystore"); + } + + #[test] + fn parse_full_with_port() { + let repo: BackupRepository = "admin@pam@backuphost:8008:tank".parse().unwrap(); + assert_eq!(repo.auth_id().to_string(), "admin@pam"); + assert_eq!(repo.host(), "backuphost"); + assert_eq!(repo.port(), 8008); + assert_eq!(repo.store(), "tank"); + } + + #[test] + fn parse_ipv4_with_port() { + let repo: BackupRepository = "192.168.1.1:1234:mystore".parse().unwrap(); + assert_eq!(repo.host(), "192.168.1.1"); + assert_eq!(repo.port(), 1234); + } + + #[test] + fn parse_ipv6_with_port() { + let repo: BackupRepository = "[ff80::1]:9007:mystore".parse().unwrap(); + assert_eq!(repo.host(), "[ff80::1]"); + assert_eq!(repo.port(), 9007); + } + + #[test] + fn parse_api_token() { + let repo: BackupRepository = "user@pbs!token@myhost:mystore".parse().unwrap(); + assert_eq!(repo.auth_id().to_string(), "user@pbs!token"); + } + + #[test] + fn parse_invalid_url_errors() { + assert!("".parse::().is_err()); + } + + #[test] + fn display_round_trip() { + for url in [ + "mystore", + "myhost:mystore", + "admin@pam@backuphost:8008:tank", + ] { + let repo: BackupRepository = url.parse().unwrap(); + assert_eq!(repo.to_string(), url, "round-trip failed for '{url}'"); + } + } + + #[test] + fn new_wraps_bare_ipv6_in_brackets() { + let repo = BackupRepository::new(None, Some("ff80::1".into()), None, "s".into()); + assert_eq!(repo.host(), "[ff80::1]"); + } + + #[test] + fn new_preserves_already_bracketed_ipv6() { + let repo = BackupRepository::new(None, Some("[ff80::1]".into()), None, "s".into()); + assert_eq!(repo.host(), "[ff80::1]"); + } +} -- 2.47.3