Skip to content

Share PostgresCluster validation tests across API versions #4220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2025

Conversation

cbandy
Copy link
Member

@cbandy cbandy commented Jul 25, 2025

As I was working a change to v1 validation, I wanted to include the v1beta1 tests so as not to introduce any regressions. I wasn't able to share tests using generics because the tests reach into specific struct fields. I was surprised to find a test failure when using unstructured, but the test was right!

So, unstructured seems like an improvement in validation testing overall:

  1. Can quickly set uninitialized fields using require.UnmarshalIntoField or unstructured.SetNestedField
  2. No struct tags that silently affect the payload

Checklist:

  • Have you added an explanation of what your changes do and why you'd like them to be included?
  • Have you updated or added documentation for the change, as applicable?
  • Have you tested your changes on all related environments with successful results, as applicable?
    • Have you added automated tests?

Type of Changes:

  • Testing enhancement

Tests are shared by manipulating unstructured values rather structs.
This exposed a bug in HBA LDAP rule validation that was masked by
"omitempty" and "omitzero" tags on struct fields.
Comment on lines +163 to +165
{ connection: hostssl, method: ldap },
{ connection: hostssl, method: ldap, options: {} },
{ connection: hostssl, method: ldap, options: { ldapbinddn: any } },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The options: {} case is what passed with v1beta1 and v1 structs but failed with unstructured. I suspect the empty object was silently being omitted, causing this case to match the one above it.

@@ -136,8 +136,8 @@ spec:
"ldapsearchattribute", or "ldapsearchfilter" options with
"ldapprefix" or "ldapsuffix" options
rule: has(self.hba) || self.method != "ldap" || !has(self.options)
|| [["ldapprefix","ldapsuffix"], ["ldapbasedn","ldapbinddn","ldapbindpasswd","ldapsearchattribute","ldapsearchfilter"]].exists_one(a,
a.exists(k, k in self.options))
|| 2 > size([["ldapprefix","ldapsuffix"], ["ldapbasedn","ldapbinddn","ldapbindpasswd","ldapsearchattribute","ldapsearchfilter"]].filter(a,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The !has(self.option) portion was being tested twice when using v1beta1 and v1 structs.

The unstructured value emitted options: {} which showed that exists_one is the wrong behavior:

  • With options: {} the field "has options" and has zero of ldapprefix, ldapbasedn, etc.
  • The correct behavior is "has options" and "at most one" of ldapprefix, ldapbasedn, etc.

Comment on lines +48 to +52
var u unstructured.Unstructured
require.UnmarshalInto(t, &u, require.Value(yaml.Marshal(base)))
assert.Equal(t, u.GetAPIVersion(), "postgres-operator.crunchydata.com/v1beta1")

testPostgresAuthenticationCommon(t, cc, u)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the pattern I used to share tests between v1beta1 and v1. Notice L82-84 of this same file.


func TestPostgresAuthenticationV1(t *testing.T) {
ctx := t.Context()
cc := require.KubernetesAtLeast(t, "1.30")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests pass with v1 on K8s before 1.30, but the plan is for v1 to be 1.30+.

@tjmoore4 tjmoore4 self-requested a review July 28, 2025 14:27
Copy link
Contributor

@tjmoore4 tjmoore4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

},
},
}) {
t.Fatalf("got %[1]T(%#[1]v)", u.Object)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 I found these links helpful

Also, for reference, a simple %v would yield

map[spec:map[nested:map[field:asdf]]]

@cbandy cbandy merged commit c95679a into CrunchyData:main Jul 28, 2025
20 checks passed
@cbandy cbandy deleted the validation-tests branch July 28, 2025 16:19
Comment on lines +81 to +82
// Correctly fails with: BUG: called without a destination
// require.UnmarshalIntoField(t, &u, `true`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover?

assert.NilError(t, cc.Create(ctx, cluster, client.DryRunAll))
})
}

func TestPostgresUserInterfaceAcrossVersions(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth renaming this file in the future? I like the specificity of the new files' names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants