From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 033FE1FF140 for ; Fri, 10 Apr 2026 17:43:13 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 769BC21E65; Fri, 10 Apr 2026 17:43:57 +0200 (CEST) From: Thomas Lamprecht To: pbs-devel@lists.proxmox.com Subject: [PATCH v4 1/5] client: repository: add tests for BackupRepository parsing Date: Fri, 10 Apr 2026 16:09:02 +0200 Message-ID: <20260410154327.4133440-2-t.lamprecht@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260410154327.4133440-1-t.lamprecht@proxmox.com> References: <20260410154327.4133440-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: 1775835763612 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.001 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 0.001 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 0.001 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 0.001 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: ESBJ4JVS56MI6HOR2NQ2BSZXZ5RVYIVV X-Message-ID-Hash: ESBJ4JVS56MI6HOR2NQ2BSZXZ5RVYIVV 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 --- unchanged 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