diff --git a/go.mod b/go.mod index a21517aa58..ade8c57452 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( k8s.io/component-base v0.31.0 k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a sigs.k8s.io/controller-runtime v0.19.3 + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd sigs.k8s.io/yaml v1.4.0 ) @@ -123,6 +124,5 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/internal/bridge/installation_test.go b/internal/bridge/installation_test.go index 28317e07f4..766233b8bb 100644 --- a/internal/bridge/installation_test.go +++ b/internal/bridge/installation_test.go @@ -18,10 +18,10 @@ import ( corev1 "k8s.io/api/core/v1" corev1apply "k8s.io/client-go/applyconfigurations/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/testing/cmp" + "github.com/crunchydata/postgres-operator/internal/testing/require" ) func TestExtractSecretContract(t *testing.T) { @@ -136,7 +136,7 @@ func TestInstallationReconcile(t *testing.T) { assert.Assert(t, cmp.Contains(applies[0], `"kind":"Secret"`)) var decoded corev1.Secret - assert.NilError(t, yaml.Unmarshal([]byte(applies[0]), &decoded)) + require.UnmarshalInto(t, &decoded, applies[0]) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"id":"abc"`)) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"secret":"xyz"`)) }) @@ -230,7 +230,7 @@ func TestInstallationReconcile(t *testing.T) { assert.Assert(t, cmp.Contains(applies[0], `"kind":"Secret"`)) var decoded corev1.Secret - assert.NilError(t, yaml.Unmarshal([]byte(applies[0]), &decoded)) + require.UnmarshalInto(t, &decoded, applies[0]) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"id":"asdf"`)) }) } @@ -326,7 +326,7 @@ func TestInstallationReconcile(t *testing.T) { assert.Assert(t, cmp.Contains(applies[0], `"kind":"Secret"`)) var decoded corev1.Secret - assert.NilError(t, yaml.Unmarshal([]byte(applies[0]), &decoded)) + require.UnmarshalInto(t, &decoded, applies[0]) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"id":"xyz"`)) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"secret":"def"`)) }) @@ -373,7 +373,7 @@ func TestInstallationReconcile(t *testing.T) { assert.Assert(t, cmp.Contains(applies[0], `"kind":"Secret"`)) var decoded corev1.Secret - assert.NilError(t, yaml.Unmarshal([]byte(applies[0]), &decoded)) + require.UnmarshalInto(t, &decoded, applies[0]) assert.Equal(t, len(decoded.Data["bridge-token"]), 0) archived := string(decoded.Data["bridge-token--2020-10-28"]) @@ -463,7 +463,7 @@ func TestInstallationReconcile(t *testing.T) { assert.Assert(t, cmp.Contains(applies[0], `"kind":"Secret"`)) var decoded corev1.Secret - assert.NilError(t, yaml.Unmarshal([]byte(applies[0]), &decoded)) + require.UnmarshalInto(t, &decoded, applies[0]) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"id":"ddd"`)) assert.Assert(t, cmp.Contains(string(decoded.Data["bridge-token"]), `"secret":"fresh"`)) }) diff --git a/internal/collector/pgadmin_test.go b/internal/collector/pgadmin_test.go index bca13d7b75..4da886abbc 100644 --- a/internal/collector/pgadmin_test.go +++ b/internal/collector/pgadmin_test.go @@ -10,13 +10,13 @@ import ( "gotest.tools/v3/assert" corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/yaml" "github.com/crunchydata/postgres-operator/internal/collector" pgadmin "github.com/crunchydata/postgres-operator/internal/controller/standalone_pgadmin" "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/testing/cmp" + "github.com/crunchydata/postgres-operator/internal/testing/require" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -125,7 +125,7 @@ collector.yaml: | ctx := feature.NewContext(context.Background(), gate) var spec v1beta1.InstrumentationSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec, `{ config: { exporters: { googlecloud: { @@ -135,7 +135,7 @@ collector.yaml: | }, }, logs: { exporters: [googlecloud] }, - }`), &spec)) + }`) configmap := new(corev1.ConfigMap) initialize.Map(&configmap.Data) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 87c522888e..a6e40adddd 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -9,8 +9,8 @@ import ( "testing" "gotest.tools/v3/assert" - "sigs.k8s.io/yaml" + "github.com/crunchydata/postgres-operator/internal/testing/require" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -54,7 +54,7 @@ func TestFetchKeyCommand(t *testing.T) { t.Run("blank", func(t *testing.T) { var spec1 v1beta1.PostgresClusterSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec1, `{ patroni: { dynamicConfiguration: { postgresql: { @@ -64,23 +64,23 @@ func TestFetchKeyCommand(t *testing.T) { }, }, }, - }`), &spec1)) + }`) assert.Equal(t, "", FetchKeyCommand(&spec1)) var spec2 v1beta1.PostgresClusterSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec2, `{ config: { parameters: { encryption_key_command: "", }, }, - }`), &spec2)) + }`) assert.Equal(t, "", FetchKeyCommand(&spec2)) }) t.Run("exists", func(t *testing.T) { var spec1 v1beta1.PostgresClusterSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec1, `{ patroni: { dynamicConfiguration: { postgresql: { @@ -90,23 +90,23 @@ func TestFetchKeyCommand(t *testing.T) { }, }, }, - }`), &spec1)) + }`) assert.Equal(t, "echo mykey", FetchKeyCommand(&spec1)) var spec2 v1beta1.PostgresClusterSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec2, `{ config: { parameters: { encryption_key_command: "cat somefile", }, }, - }`), &spec2)) + }`) assert.Equal(t, "cat somefile", FetchKeyCommand(&spec2)) }) t.Run("config.parameters takes precedence", func(t *testing.T) { var spec v1beta1.PostgresClusterSpec - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &spec, `{ config: { parameters: { encryption_key_command: "cat somefile", @@ -121,7 +121,7 @@ func TestFetchKeyCommand(t *testing.T) { }, }, }, - }`), &spec)) + }`) assert.Equal(t, "cat somefile", FetchKeyCommand(&spec)) }) } @@ -139,9 +139,9 @@ func TestPGAdminContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_PGADMIN", "env-var-pgadmin") assert.Equal(t, PGAdminContainerImage(cluster), "env-var-pgadmin") - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &cluster.Spec, `{ userInterface: { pgAdmin: { image: spec-image } }, - }`), &cluster.Spec)) + }`) assert.Equal(t, PGAdminContainerImage(cluster), "spec-image") } @@ -158,9 +158,9 @@ func TestPGBackRestContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_PGBACKREST", "env-var-pgbackrest") assert.Equal(t, PGBackRestContainerImage(cluster), "env-var-pgbackrest") - assert.NilError(t, yaml.Unmarshal([]byte(`{ - backups: { pgBackRest: { image: spec-image } }, - }`), &cluster.Spec)) + require.UnmarshalInto(t, &cluster.Spec, `{ + backups: { pgbackrest: { image: spec-image } }, + }`) assert.Equal(t, PGBackRestContainerImage(cluster), "spec-image") } @@ -177,9 +177,9 @@ func TestPGBouncerContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_PGBOUNCER", "env-var-pgbouncer") assert.Equal(t, PGBouncerContainerImage(cluster), "env-var-pgbouncer") - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &cluster.Spec, `{ proxy: { pgBouncer: { image: spec-image } }, - }`), &cluster.Spec)) + }`) assert.Equal(t, PGBouncerContainerImage(cluster), "spec-image") } @@ -196,9 +196,9 @@ func TestPGExporterContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_PGEXPORTER", "env-var-pgexporter") assert.Equal(t, PGExporterContainerImage(cluster), "env-var-pgexporter") - assert.NilError(t, yaml.Unmarshal([]byte(`{ - monitoring: { pgMonitor: { exporter: { image: spec-image } } }, - }`), &cluster.Spec)) + require.UnmarshalInto(t, &cluster.Spec, `{ + monitoring: { pgmonitor: { exporter: { image: spec-image } } }, + }`) assert.Equal(t, PGExporterContainerImage(cluster), "spec-image") } @@ -215,9 +215,9 @@ func TestStandalonePGAdminContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_STANDALONE_PGADMIN", "env-var-pgadmin") assert.Equal(t, StandalonePGAdminContainerImage(pgadmin), "env-var-pgadmin") - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &pgadmin.Spec, `{ image: spec-image - }`), &pgadmin.Spec)) + }`) assert.Equal(t, StandalonePGAdminContainerImage(pgadmin), "spec-image") } diff --git a/internal/controller/pgupgrade/jobs_test.go b/internal/controller/pgupgrade/jobs_test.go index 664c1c5346..c3f3608e4d 100644 --- a/internal/controller/pgupgrade/jobs_test.go +++ b/internal/controller/pgupgrade/jobs_test.go @@ -19,6 +19,7 @@ import ( "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/testing/cmp" + "github.com/crunchydata/postgres-operator/internal/testing/require" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -54,7 +55,7 @@ func TestLargestWholeCPU(t *testing.T) { } { t.Run(tt.Name, func(t *testing.T) { var resources corev1.ResourceRequirements - assert.NilError(t, yaml.Unmarshal([]byte(tt.ResourcesYAML), &resources)) + require.UnmarshalInto(t, &resources, tt.ResourcesYAML) assert.Equal(t, tt.Result, largestWholeCPU(resources)) }) } @@ -383,8 +384,7 @@ func TestPGUpgradeContainerImage(t *testing.T) { t.Setenv("RELATED_IMAGE_PGUPGRADE", "env-var-pgbackrest") assert.Equal(t, pgUpgradeContainerImage(upgrade), "env-var-pgbackrest") - assert.NilError(t, yaml.Unmarshal( - []byte(`{ image: spec-image }`), &upgrade.Spec)) + require.UnmarshalInto(t, &upgrade.Spec, `{ image: spec-image }`) assert.Equal(t, pgUpgradeContainerImage(upgrade), "spec-image") } diff --git a/internal/controller/postgrescluster/postgres_test.go b/internal/controller/postgrescluster/postgres_test.go index a6966fc802..c14e68851b 100644 --- a/internal/controller/postgrescluster/postgres_test.go +++ b/internal/controller/postgrescluster/postgres_test.go @@ -21,7 +21,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/feature" @@ -198,9 +197,9 @@ func TestGeneratePostgresUserSecret(t *testing.T) { }) t.Run("PgBouncer", func(t *testing.T) { - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &cluster.Spec, `{ proxy: { pgBouncer: { port: 10220 } }, - }`), &cluster.Spec)) + }`) secret, err := reconciler.generatePostgresUserSecret(cluster, spec, nil) assert.NilError(t, err) @@ -250,14 +249,14 @@ func TestReconcilePostgresVolumes(t *testing.T) { t.Cleanup(func() { assert.Check(t, tClient.Delete(ctx, cluster)) }) spec := &v1beta1.PostgresInstanceSetSpec{} - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, spec, `{ name: "some-instance", dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } }, storageClassName: "storage-class-for-data", }, - }`), spec)) + }`) instance := &appsv1.StatefulSet{ObjectMeta: naming.GenerateInstance(cluster, spec)} pvc, err := reconciler.reconcilePostgresDataVolume(ctx, cluster, spec, instance, nil, nil) @@ -290,14 +289,14 @@ volumeMode: Filesystem t.Cleanup(func() { assert.Check(t, tClient.Delete(ctx, cluster)) }) spec := &v1beta1.PostgresInstanceSetSpec{} - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, spec, `{ name: "some-instance", dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } }, storageClassName: "storage-class-for-data", }, - }`), spec)) + }`) instance := &appsv1.StatefulSet{ObjectMeta: naming.GenerateInstance(cluster, spec)} recorder := events.NewRecorder(t, runtime.Scheme) @@ -392,14 +391,14 @@ volumeMode: Filesystem t.Cleanup(func() { assert.Check(t, tClient.Delete(ctx, cluster)) }) spec := &v1beta1.PostgresInstanceSetSpec{} - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, spec, `{ name: "some-instance", dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } }, storageClassName: "storage-class-for-data", }, - }`), spec)) + }`) instance := &appsv1.StatefulSet{ObjectMeta: naming.GenerateInstance(cluster, spec)} recorder := events.NewRecorder(t, runtime.Scheme) @@ -455,14 +454,14 @@ volumeMode: Filesystem t.Cleanup(func() { assert.Check(t, tClient.Delete(ctx, cluster)) }) spec := &v1beta1.PostgresInstanceSetSpec{} - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, spec, `{ name: "some-instance", dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } }, storageClassName: "storage-class-for-data", }, - }`), spec)) + }`) instance := &appsv1.StatefulSet{ObjectMeta: naming.GenerateInstance(cluster, spec)} observed := &Instance{} @@ -475,13 +474,13 @@ volumeMode: Filesystem t.Run("Specified", func(t *testing.T) { spec := spec.DeepCopy() - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, spec, `{ walVolumeClaimSpec: { accessModes: [ReadWriteMany], resources: { requests: { storage: 2Gi } }, storageClassName: "storage-class-for-wal", }, - }`), spec)) + }`) pvc, err := reconciler.reconcilePostgresWALVolume(ctx, cluster, spec, instance, observed, nil) assert.NilError(t, err) diff --git a/internal/patroni/config_test.go b/internal/patroni/config_test.go index b63acdeec0..d69edf8da1 100644 --- a/internal/patroni/config_test.go +++ b/internal/patroni/config_test.go @@ -263,7 +263,7 @@ func TestDynamicConfiguration(t *testing.T) { expected: map[string]any{ "loop_wait": int32(10), "ttl": int32(30), - "retry_timeout": float64(5), + "retry_timeout": int64(5), "postgresql": map[string]any{ "parameters": map[string]any{}, "pg_hba": []string{}, @@ -380,7 +380,7 @@ func TestDynamicConfiguration(t *testing.T) { "postgresql": map[string]any{ "parameters": map[string]any{ "something": "str", - "another": float64(5), + "another": int64(5), }, "pg_hba": []string{}, "use_pg_rewind": true, @@ -413,7 +413,7 @@ func TestDynamicConfiguration(t *testing.T) { "postgresql": map[string]any{ "parameters": map[string]any{ "something": intstr.FromString("this"), - "another": float64(5), + "another": int64(5), }, "pg_hba": []string{}, "use_pg_rewind": true, @@ -909,7 +909,7 @@ func TestDynamicConfiguration(t *testing.T) { } { t.Run(tt.name, func(t *testing.T) { cluster := new(v1beta1.PostgresCluster) - assert.NilError(t, yaml.Unmarshal([]byte(tt.spec), &cluster.Spec)) + require.UnmarshalInto(t, &cluster.Spec, tt.spec) if cluster.Spec.PostgresVersion == 0 { cluster.Spec.PostgresVersion = 14 } diff --git a/internal/testing/require/encoding.go b/internal/testing/require/encoding.go new file mode 100644 index 0000000000..a99f7a42f1 --- /dev/null +++ b/internal/testing/require/encoding.go @@ -0,0 +1,39 @@ +// Copyright 2021 - 2025 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +package require + +import ( + "errors" + "testing" + + "gotest.tools/v3/assert" + "sigs.k8s.io/json" + "sigs.k8s.io/yaml" +) + +// UnmarshalInto parses input as YAML (or JSON) the same way as the Kubernetes +// API Server writing into output. It calls t.Fatal when something fails. +func UnmarshalInto[Data ~string | ~[]byte, Destination *T, T any]( + t testing.TB, output Destination, input Data, +) { + t.Helper() + + // The REST API uses serializers: + // + // https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime/serializer/json + // https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime/serializer/yaml + // + // The util package follows similar paths (strict, preserve ints, etc.) + // + // https://pkg.go.dev/k8s.io/apimachinery/pkg/util/json + // https://pkg.go.dev/k8s.io/apimachinery/pkg/util/yaml + + data, err := yaml.YAMLToJSONStrict([]byte(input)) + assert.NilError(t, err) + + strict, err := json.UnmarshalStrict(data, output) + assert.NilError(t, err) + assert.NilError(t, errors.Join(strict...)) +} diff --git a/internal/testing/require/encoding_test.go b/internal/testing/require/encoding_test.go new file mode 100644 index 0000000000..b7c287c1c2 --- /dev/null +++ b/internal/testing/require/encoding_test.go @@ -0,0 +1,40 @@ +// Copyright 2021 - 2025 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "reflect" + "testing" + + "github.com/crunchydata/postgres-operator/internal/testing/require" +) + +func TestUnmarshalInto(t *testing.T) { + for _, tt := range []struct { + input string + expected any + }{ + // Any fraction that amounts to an integral number is converted to an integer. + // See: https://go.dev/play/p/dvXRVhYO8UH + {input: `3`, expected: int64(3)}, + {input: `3.000`, expected: int64(3)}, + {input: `0.03e2`, expected: int64(3)}, + {input: `{a: 5}`, expected: map[string]any{"a": int64(5)}}, + {input: `{a: 5.000}`, expected: map[string]any{"a": int64(5)}}, + {input: `{a: 0.05e2}`, expected: map[string]any{"a": int64(5)}}, + + // YAML or JSON + {input: `asdf`, expected: "asdf"}, + {input: `"asdf"`, expected: "asdf"}, + {input: `[1, 2.3, true]`, expected: []any{int64(1), float64(2.3), true}}, + } { + sink := reflect.Zero(reflect.TypeOf(tt.expected)).Interface() + require.UnmarshalInto(t, &sink, tt.input) + + if !reflect.DeepEqual(tt.expected, sink) { + t.Fatalf("expected %[1]T(%#[1]v), got %[2]T(%#[2]v)", tt.expected, sink) + } + } +} diff --git a/internal/testing/validation/pgadmin_test.go b/internal/testing/validation/pgadmin_test.go index d2ba6e095f..aa5cdb42e1 100644 --- a/internal/testing/validation/pgadmin_test.go +++ b/internal/testing/validation/pgadmin_test.go @@ -12,7 +12,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/testing/cmp" @@ -35,11 +34,11 @@ func TestPGAdminInstrumentation(t *testing.T) { t.Run("LogsRetentionPeriod", func(t *testing.T) { pgadmin := base.DeepCopy() - assert.NilError(t, yaml.UnmarshalStrict([]byte(`{ + require.UnmarshalInto(t, &pgadmin.Spec, `{ instrumentation: { logs: { retentionPeriod: 5m }, }, - }`), &pgadmin.Spec)) + }`) err := cc.Create(ctx, pgadmin, client.DryRunAll) assert.Assert(t, apierrors.IsInvalid(err)) diff --git a/internal/testing/validation/postgrescluster_test.go b/internal/testing/validation/postgrescluster_test.go index 17825c2f46..30b6cff373 100644 --- a/internal/testing/validation/postgrescluster_test.go +++ b/internal/testing/validation/postgrescluster_test.go @@ -14,7 +14,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/testing/cmp" @@ -31,7 +30,7 @@ func TestPostgresConfigParameters(t *testing.T) { base := v1beta1.NewPostgresCluster() // Start with a bunch of required fields. - assert.NilError(t, yaml.Unmarshal([]byte(`{ + require.UnmarshalInto(t, &base.Spec, `{ postgresVersion: 16, backups: { pgbackrest: { @@ -44,7 +43,7 @@ func TestPostgresConfigParameters(t *testing.T) { resources: { requests: { storage: 1Mi } }, }, }], - }`), &base.Spec)) + }`) base.Namespace = namespace.Name base.Name = "postgres-config-parameters" @@ -217,7 +216,7 @@ func TestPostgresUserOptions(t *testing.T) { base := v1beta1.NewPostgresCluster() // Start with a bunch of required fields. - assert.NilError(t, yaml.UnmarshalStrict([]byte(`{ + require.UnmarshalInto(t, &base.Spec, `{ postgresVersion: 16, backups: { pgbackrest: { @@ -230,7 +229,7 @@ func TestPostgresUserOptions(t *testing.T) { resources: { requests: { storage: 1Mi } }, }, }], - }`), &base.Spec)) + }`) base.Namespace = namespace.Name base.Name = "postgres-user-options" diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go index 1dde5359a0..5f50e0cb50 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go @@ -23,13 +23,13 @@ func TestDurationYAML(t *testing.T) { assert.DeepEqual(t, zero, []byte(`"0"`+"\n")) var parsed Duration - assert.NilError(t, yaml.Unmarshal(zero, &parsed)) + assert.NilError(t, yaml.UnmarshalStrict(zero, &parsed)) assert.Equal(t, parsed.AsDuration().Duration, 0*time.Second) }) t.Run("Small", func(t *testing.T) { var parsed Duration - assert.NilError(t, yaml.Unmarshal([]byte(`3ns`), &parsed)) + assert.NilError(t, yaml.UnmarshalStrict([]byte(`3ns`), &parsed)) assert.Equal(t, parsed.AsDuration().Duration, 3*time.Nanosecond) b, err := yaml.Marshal(parsed) @@ -39,7 +39,7 @@ func TestDurationYAML(t *testing.T) { t.Run("Large", func(t *testing.T) { var parsed Duration - assert.NilError(t, yaml.Unmarshal([]byte(`52 weeks`), &parsed)) + assert.NilError(t, yaml.UnmarshalStrict([]byte(`52 weeks`), &parsed)) assert.Equal(t, parsed.AsDuration().Duration, 364*24*time.Hour) b, err := yaml.Marshal(parsed) @@ -109,7 +109,7 @@ func TestDurationYAML(t *testing.T) { {"PT2D9H", (2 * Day) + 9*time.Hour}, } { var parsed Duration - assert.NilError(t, yaml.Unmarshal([]byte(tt.input), &parsed)) + assert.NilError(t, yaml.UnmarshalStrict([]byte(tt.input), &parsed)) assert.Equal(t, parsed.AsDuration().Duration, tt.result) // This is what Kubernetes calls when validating the "duration" format. @@ -132,7 +132,7 @@ func TestDurationYAML(t *testing.T) { "11 wks", } { assert.ErrorContains(t, - yaml.Unmarshal([]byte(tt), new(Duration)), "unable to parse") + yaml.UnmarshalStrict([]byte(tt), new(Duration)), "unable to parse") // This is what Kubernetes calls when validating the "duration" format. // - https://releases.k8s.io/v1.32.0/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation/validation.go#L116 @@ -142,7 +142,7 @@ func TestDurationYAML(t *testing.T) { t.Run("DoNotUsePartialAmounts", func(t *testing.T) { var parsed Duration - assert.NilError(t, yaml.Unmarshal([]byte(`1.5 hours`), &parsed)) + assert.NilError(t, yaml.UnmarshalStrict([]byte(`1.5 hours`), &parsed)) expected, err := time.ParseDuration(`1.5h`) assert.NilError(t, err) @@ -160,7 +160,7 @@ func TestSchemalessObjectDeepCopy(t *testing.T) { assert.DeepEqual(t, z, z.DeepCopy()) var one SchemalessObject - assert.NilError(t, yaml.Unmarshal( + assert.NilError(t, yaml.UnmarshalStrict( []byte(`{ str: value, num: 1, arr: [a, 2, true] }`), &one, ))