From: Lukas Wagner <l.wagner@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH datacenter-manager 3/3] views: tests: use full section-config format for test cases
Date: Mon, 17 Nov 2025 15:11:22 +0100 [thread overview]
Message-ID: <20251117141122.328559-4-l.wagner@proxmox.com> (raw)
In-Reply-To: <20251117141122.328559-1-l.wagner@proxmox.com>
The config structure should be more stable than the actual rust types,
so this should lead to less maintenance burden over time. Also, the
tests are a bit easier to read this way.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
server/src/views/tests.rs | 378 +++++++++++++++++++-------------------
1 file changed, 186 insertions(+), 192 deletions(-)
diff --git a/server/src/views/tests.rs b/server/src/views/tests.rs
index 0d83ae70..9f496207 100644
--- a/server/src/views/tests.rs
+++ b/server/src/views/tests.rs
@@ -1,7 +1,8 @@
use pdm_api_types::{
- resource::{PveLxcResource, PveQemuResource, PveStorageResource, Resource, ResourceType},
- views::{EnumMatcher, FilterRule, StringMatcher, ViewConfig},
+ resource::{PveLxcResource, PveQemuResource, PveStorageResource, Resource},
+ views::{ViewConfig, ViewConfigEntry},
};
+use proxmox_section_config::typed::ApiSectionDataEntry;
use super::View;
@@ -79,20 +80,26 @@ fn run_test(config: ViewConfig, tests: &[((&str, &Resource), bool)]) {
}
}
+fn parse_config(config: &str) -> ViewConfig {
+ let config = ViewConfigEntry::parse_section_config("views.cfg", config).unwrap();
+ let ViewConfigEntry::View(config) = config.get("test").unwrap();
+ config.clone()
+}
+
const NODE: &str = "somenode";
const STORAGE: &str = "somestorage";
const REMOTE: &str = "someremote";
#[test]
fn include_remotes() {
- let config = ViewConfig {
- id: "only-includes".into(),
- include: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-a".into())),
- FilterRule::Remote(StringMatcher::Exact("remote-b".into())),
- ],
- ..Default::default()
- };
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-a
+ include remote=remote-b
+",
+ );
+
run_test(
config.clone(),
&[
@@ -129,15 +136,14 @@ fn include_remotes() {
#[test]
fn exclude_remotes() {
- let config = ViewConfig {
- id: "only-excludes".into(),
- exclude: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-a".into())),
- FilterRule::Remote(StringMatcher::Exact("remote-b".into())),
- ],
- include_all: Some(true),
- ..Default::default()
- };
+ let config = parse_config(
+ "
+view: test
+ include-all true
+ exclude remote=remote-a
+ exclude remote=remote-b
+",
+ );
run_test(
config.clone(),
@@ -175,19 +181,16 @@ fn exclude_remotes() {
#[test]
fn include_exclude_remotes() {
- let config = ViewConfig {
- id: "both".into(),
- include: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-a".into())),
- FilterRule::Remote(StringMatcher::Exact("remote-b".into())),
- ],
- exclude: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-b".into())),
- FilterRule::Remote(StringMatcher::Exact("remote-c".into())),
- ],
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-a
+ include remote=remote-b
+ exclude remote=remote-b
+ exclude remote=remote-c
+",
+ );
- ..Default::default()
- };
run_test(
config.clone(),
&[
@@ -225,11 +228,12 @@ fn include_exclude_remotes() {
#[test]
fn empty_config() {
- let config = ViewConfig {
- id: "empty".into(),
- include_all: Some(true),
- ..Default::default()
- };
+ let config = parse_config(
+ "
+view: test
+ include-all true
+",
+ );
run_test(
config.clone(),
&[
@@ -270,15 +274,15 @@ fn empty_config() {
#[test]
fn include_type() {
+ let config = parse_config(
+ "
+view: test
+ include resource-type=storage
+ include resource-type=qemu
+",
+ );
run_test(
- ViewConfig {
- id: "include-resource-type".into(),
- include: vec![
- FilterRule::ResourceType(EnumMatcher(ResourceType::PveStorage)),
- FilterRule::ResourceType(EnumMatcher(ResourceType::PveQemu)),
- ],
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -298,16 +302,16 @@ fn include_type() {
#[test]
fn exclude_type() {
+ let config = parse_config(
+ "
+view: test
+ include-all true
+ exclude resource-type=storage
+ exclude resource-type=qemu
+",
+ );
run_test(
- ViewConfig {
- id: "exclude-resource-type".into(),
- exclude: vec![
- FilterRule::ResourceType(EnumMatcher(ResourceType::PveStorage)),
- FilterRule::ResourceType(EnumMatcher(ResourceType::PveQemu)),
- ],
- include_all: Some(true),
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -327,15 +331,16 @@ fn exclude_type() {
#[test]
fn include_exclude_type() {
+ let config = parse_config(
+ "
+view: test
+ include resource-type=qemu
+ exclude resource-type=storage
+",
+ );
+
run_test(
- ViewConfig {
- id: "exclude-resource-type".into(),
- include: vec![FilterRule::ResourceType(EnumMatcher(ResourceType::PveQemu))],
- exclude: vec![FilterRule::ResourceType(EnumMatcher(
- ResourceType::PveStorage,
- ))],
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -355,16 +360,16 @@ fn include_exclude_type() {
#[test]
fn include_exclude_tags() {
+ let config = parse_config(
+ "
+view: test
+ include tag=tag1
+ include tag=tag2
+ exclude tag=tag3
+",
+ );
run_test(
- ViewConfig {
- id: "include-tags".into(),
- include: vec![
- FilterRule::Tag(StringMatcher::Exact("tag1".to_string())),
- FilterRule::Tag(StringMatcher::Exact("tag2".to_string())),
- ],
- exclude: vec![FilterRule::Tag(StringMatcher::Exact("tag3".to_string()))],
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -401,18 +406,16 @@ fn include_exclude_tags() {
#[test]
fn include_exclude_resource_pool() {
+ let config = parse_config(
+ "
+view: test
+ include resource-pool=pool1
+ include resource-pool=pool2
+ exclude resource-pool=pool2
+",
+ );
run_test(
- ViewConfig {
- id: "pools".into(),
- include: vec![
- FilterRule::ResourcePool(StringMatcher::Exact("pool1".to_string())),
- FilterRule::ResourcePool(StringMatcher::Exact("pool2".to_string())),
- ],
- exclude: vec![FilterRule::ResourcePool(StringMatcher::Exact(
- "pool2".to_string(),
- ))],
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -449,26 +452,18 @@ fn include_exclude_resource_pool() {
#[test]
fn include_exclude_resource_id() {
+ let config = parse_config(
+ "
+view: test
+ include resource-id=remote/someremote/guest/100
+ include resource-id=remote/someremote/storage/somenode/somestorage
+ exclude resource-id=remote/someremote/guest/101
+ exclude resource-id=remote/otherremote/guest/101
+ exclude resource-id=remote/someremote/storage/somenode/otherstorage
+",
+ );
run_test(
- ViewConfig {
- id: "resource-id".into(),
- include: vec![
- FilterRule::ResourceId(StringMatcher::Exact(format!("remote/{REMOTE}/guest/100"))),
- FilterRule::ResourceId(StringMatcher::Exact(format!(
- "remote/{REMOTE}/storage/{NODE}/{STORAGE}"
- ))),
- ],
- exclude: vec![
- FilterRule::ResourceId(StringMatcher::Exact(format!("remote/{REMOTE}/guest/101"))),
- FilterRule::ResourceId(StringMatcher::Exact(
- "remote/otherremote/guest/101".to_string(),
- )),
- FilterRule::ResourceId(StringMatcher::Exact(format!(
- "remote/{REMOTE}/storage/{NODE}/otherstorage"
- ))),
- ],
- ..Default::default()
- },
+ config,
&[
(
(REMOTE, &make_storage_resource(REMOTE, NODE, STORAGE)),
@@ -506,20 +501,16 @@ fn include_exclude_resource_id() {
#[test]
fn node_included() {
- let view = View::new(ViewConfig {
- id: "both".into(),
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-a
+ include resource-id=remote/someremote/node/test
+ exclude remote=remote-b
+",
+ );
- include: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-a".to_string())),
- FilterRule::ResourceId(StringMatcher::Exact(
- "remote/someremote/node/test".to_string(),
- )),
- ],
- exclude: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- ..Default::default()
- });
+ let view = View::new(config);
assert!(view.is_node_included("remote-a", "somenode"));
assert!(view.is_node_included("remote-a", "somenode2"));
@@ -527,19 +518,19 @@ fn node_included() {
assert!(!view.is_node_included("remote-b", "somenode2"));
assert!(view.is_node_included("someremote", "test"));
- assert_eq!(view.name(), "both");
+ assert_eq!(view.name(), "test");
}
#[test]
fn can_skip_remote_if_excluded() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![],
- exclude: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- include_all: Some(true),
- });
+ let config = parse_config(
+ "
+view: test
+ include-all true
+ exclude remote=remote-b
+",
+ );
+ let view = View::new(config);
assert!(!view.can_skip_remote("remote-a"));
assert!(view.can_skip_remote("remote-b"));
@@ -547,14 +538,14 @@ fn can_skip_remote_if_excluded() {
#[test]
fn can_skip_remote_if_included() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- exclude: vec![],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-b
+",
+ );
+
+ let view = View::new(config);
assert!(!view.can_skip_remote("remote-b"));
assert!(view.can_skip_remote("remote-a"));
@@ -562,17 +553,15 @@ fn can_skip_remote_if_included() {
#[test]
fn can_skip_remote_cannot_skip_if_any_other_include() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![
- FilterRule::Remote(StringMatcher::Exact("remote-b".to_string())),
- FilterRule::ResourceId(StringMatcher::Exact(
- "resource/remote-a/guest/100".to_string(),
- )),
- ],
- exclude: vec![],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-b
+ include resource-id=remote/remote-a/guest/100
+",
+ );
+
+ let view = View::new(config);
assert!(!view.can_skip_remote("remote-b"));
assert!(!view.can_skip_remote("remote-a"));
@@ -580,26 +569,28 @@ fn can_skip_remote_cannot_skip_if_any_other_include() {
#[test]
fn can_skip_remote_explicit_remote_exclude() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![FilterRule::ResourceId(StringMatcher::Exact(
- "resource/remote-a/guest/100".to_string(),
- ))],
- exclude: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-a".to_string(),
- ))],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ exclude remote=remote-a
+ include resource-id=remote/remote-a/guest/100
+",
+ );
+
+ let view = View::new(config);
assert!(view.can_skip_remote("remote-a"));
}
#[test]
fn can_skip_remote_with_empty_config() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+",
+ );
+
+ let view = View::new(config);
assert!(view.can_skip_remote("remote-a"));
assert!(view.can_skip_remote("remote-b"));
@@ -607,11 +598,14 @@ fn can_skip_remote_with_empty_config() {
#[test]
fn can_skip_remote_cannot_skip_if_all_included() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include_all: Some(true),
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include-all true
+",
+ );
+
+ let view = View::new(config);
assert!(!view.can_skip_remote("remote-a"));
assert!(!view.can_skip_remote("remote-b"));
@@ -619,14 +613,14 @@ fn can_skip_remote_cannot_skip_if_all_included() {
#[test]
fn can_skip_remote_with_no_remote_includes() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![FilterRule::ResourceId(StringMatcher::Exact(
- "resource/remote-a/guest/100".to_string(),
- ))],
- exclude: vec![],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include resource-id=remote/remote-a/guest/100
+",
+ );
+
+ let view = View::new(config);
assert!(!view.can_skip_remote("remote-a"));
assert!(!view.can_skip_remote("remote-b"));
@@ -634,42 +628,42 @@ fn can_skip_remote_with_no_remote_includes() {
#[test]
fn explicitly_included_remote() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- exclude: vec![],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-b
+",
+ );
+
+ let view = View::new(config);
assert!(view.is_remote_explicitly_included("remote-b"));
}
#[test]
fn included_and_excluded_same_remote() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- exclude: vec![FilterRule::Remote(StringMatcher::Exact(
- "remote-b".to_string(),
- ))],
- ..Default::default()
- });
+ let config = parse_config(
+ "
+view: test
+ include remote=remote-b
+ exclude remote=remote-b
+",
+ );
+
+ let view = View::new(config);
assert!(!view.is_remote_explicitly_included("remote-b"));
}
#[test]
fn not_explicitly_included_remote() {
- let view = View::new(ViewConfig {
- id: "abc".into(),
- include: vec![],
- exclude: vec![],
- include_all: Some(true),
- });
+ let config = parse_config(
+ "
+view: test
+ include-all true
+",
+ );
+ let view = View::new(config);
// Assert that is not *explicitly* included
assert!(view.is_remote_explicitly_included("remote-b"));
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
prev parent reply other threads:[~2025-11-17 14:12 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-17 14:11 [pdm-devel] [PATCH datacenter-manager 0/3] views: preparations for regex/glob, include-all param Lukas Wagner
2025-11-17 14:11 ` [pdm-devel] [PATCH datacenter-manager 1/3] pdm-api-types: views: preparations for future glob/regex support Lukas Wagner
2025-11-17 14:11 ` [pdm-devel] [PATCH datacenter-manager 2/3] views: add 'include-all' param; change semantics when there are no includes Lukas Wagner
2025-11-17 14:11 ` Lukas Wagner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251117141122.328559-4-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox