Skip to content

Commit b5711e5

Browse files
committed
Add TestPostgresClusterInstrumentation validation test
1 parent 31574a2 commit b5711e5

1 file changed

Lines changed: 205 additions & 0 deletions

File tree

internal/crd/validation/postgrescluster_test.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sigs.k8s.io/controller-runtime/pkg/client"
1515
"sigs.k8s.io/yaml"
1616

17+
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
1718
"github.com/crunchydata/postgres-operator/internal/testing/cmp"
1819
"github.com/crunchydata/postgres-operator/internal/testing/require"
1920
v1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1"
@@ -292,3 +293,207 @@ func TestAdditionalVolumes(t *testing.T) {
292293
assert.NilError(t, dryrun.Create(ctx, tmp.DeepCopy()))
293294
})
294295
}
296+
297+
func TestPostgresClusterInstrumentation(t *testing.T) {
298+
ctx := context.Background()
299+
cc := require.Kubernetes(t)
300+
t.Parallel()
301+
302+
namespace := require.Namespace(t, cc)
303+
base := v1beta1.NewPostgresCluster()
304+
base.Namespace = namespace.Name
305+
base.Name = "postgres-instrumentation"
306+
require.UnmarshalInto(t, &base.Spec, `{
307+
postgresVersion: 16,
308+
instances: [{
309+
dataVolumeClaimSpec: {
310+
accessModes: [ReadWriteOnce],
311+
resources: { requests: { storage: 1Mi } },
312+
},
313+
}],
314+
}`)
315+
316+
assert.NilError(t, cc.Create(ctx, base.DeepCopy(), client.DryRunAll),
317+
"expected this base to be valid")
318+
319+
t.Run("LogsBatches", func(t *testing.T) {
320+
t.Run("Disable", func(t *testing.T) {
321+
for _, tt := range []struct {
322+
batches string
323+
valid bool
324+
}{
325+
{valid: true, batches: ``}, // both null
326+
{valid: true, batches: `minRecords: 1`}, // one null
327+
{valid: true, batches: `maxDelay: 1s`}, // other null
328+
329+
{valid: false, batches: `minRecords: 0`}, // one zero
330+
{valid: false, batches: `maxDelay: 0m`}, // other zero
331+
332+
{valid: true, batches: `minRecords: 0, maxDelay: 0m`}, // both zero
333+
{valid: true, batches: `minRecords: 1, maxDelay: 1s`}, // both non-zero
334+
} {
335+
cluster := base.DeepCopy()
336+
require.UnmarshalInto(t, &cluster.Spec.Instrumentation, `{
337+
logs: { batches: { `+tt.batches+` } }
338+
}`)
339+
340+
err := cc.Create(ctx, cluster, client.DryRunAll)
341+
if tt.valid {
342+
assert.NilError(t, err)
343+
} else {
344+
assert.Assert(t, apierrors.IsInvalid(err))
345+
assert.ErrorContains(t, err, "disable")
346+
assert.ErrorContains(t, err, "minRecords")
347+
assert.ErrorContains(t, err, "maxDelay")
348+
349+
details := require.StatusErrorDetails(t, err)
350+
assert.Assert(t, cmp.Len(details.Causes, 1))
351+
352+
for _, cause := range details.Causes {
353+
assert.Equal(t, cause.Field, "spec.instrumentation.logs.batches")
354+
assert.Assert(t, cmp.Contains(cause.Message, "disable batching"))
355+
assert.Assert(t, cmp.Contains(cause.Message, "minRecords and maxDelay must be zero"))
356+
}
357+
}
358+
}
359+
})
360+
361+
t.Run("MaxDelay", func(t *testing.T) {
362+
cluster := base.DeepCopy()
363+
require.UnmarshalInto(t, &cluster.Spec.Instrumentation, `{
364+
logs: {
365+
batches: { maxDelay: 100min },
366+
},
367+
}`)
368+
369+
err := cc.Create(ctx, cluster, client.DryRunAll)
370+
assert.Assert(t, apierrors.IsInvalid(err))
371+
assert.ErrorContains(t, err, "maxDelay")
372+
assert.ErrorContains(t, err, "5m")
373+
374+
details := require.StatusErrorDetails(t, err)
375+
assert.Assert(t, cmp.Len(details.Causes, 1))
376+
377+
for _, cause := range details.Causes {
378+
assert.Equal(t, cause.Field, "spec.instrumentation.logs.batches.maxDelay")
379+
}
380+
})
381+
382+
t.Run("MinMaxRecords", func(t *testing.T) {
383+
cluster := base.DeepCopy()
384+
require.UnmarshalInto(t, &cluster.Spec.Instrumentation, `{
385+
logs: {
386+
batches: { minRecords: -11, maxRecords: 0 },
387+
},
388+
}`)
389+
390+
err := cc.Create(ctx, cluster, client.DryRunAll)
391+
assert.Assert(t, apierrors.IsInvalid(err))
392+
assert.ErrorContains(t, err, "minRecords")
393+
assert.ErrorContains(t, err, "greater than or equal to 0")
394+
assert.ErrorContains(t, err, "maxRecords")
395+
assert.ErrorContains(t, err, "greater than or equal to 1")
396+
397+
details := require.StatusErrorDetails(t, err)
398+
assert.Assert(t, cmp.Len(details.Causes, 2))
399+
400+
for _, cause := range details.Causes {
401+
switch cause.Field {
402+
case "spec.instrumentation.logs.batches.maxRecords":
403+
assert.Assert(t, cmp.Contains(cause.Message, "0"))
404+
assert.Assert(t, cmp.Contains(cause.Message, "greater than or equal to 1"))
405+
406+
case "spec.instrumentation.logs.batches.minRecords":
407+
assert.Assert(t, cmp.Contains(cause.Message, "-11"))
408+
assert.Assert(t, cmp.Contains(cause.Message, "greater than or equal to 0"))
409+
}
410+
}
411+
412+
t.Run("Reversed", func(t *testing.T) {
413+
for _, batches := range []string{
414+
`maxRecords: 99`, // default minRecords
415+
`minRecords: 99, maxRecords: 21`, //
416+
} {
417+
cluster := base.DeepCopy()
418+
require.UnmarshalInto(t, &cluster.Spec.Instrumentation, `{
419+
logs: {
420+
batches: { `+batches+` },
421+
},
422+
}`)
423+
424+
err := cc.Create(ctx, cluster, client.DryRunAll)
425+
assert.Assert(t, apierrors.IsInvalid(err))
426+
assert.ErrorContains(t, err, "minRecords")
427+
assert.ErrorContains(t, err, "maxRecords")
428+
429+
details := require.StatusErrorDetails(t, err)
430+
assert.Assert(t, cmp.Len(details.Causes, 1))
431+
432+
for _, cause := range details.Causes {
433+
assert.Equal(t, cause.Field, "spec.instrumentation.logs.batches")
434+
assert.Assert(t, cmp.Contains(cause.Message, "minRecords cannot be larger than maxRecords"))
435+
}
436+
}
437+
})
438+
})
439+
})
440+
441+
t.Run("LogsRetentionPeriod", func(t *testing.T) {
442+
cluster := base.DeepCopy()
443+
require.UnmarshalInto(t, &cluster.Spec, `{
444+
instrumentation: {
445+
logs: { retentionPeriod: 5m },
446+
},
447+
}`)
448+
449+
err := cc.Create(ctx, cluster, client.DryRunAll)
450+
assert.Assert(t, apierrors.IsInvalid(err))
451+
assert.ErrorContains(t, err, "retentionPeriod")
452+
assert.ErrorContains(t, err, "hour|day|week")
453+
assert.ErrorContains(t, err, "one hour")
454+
455+
details := require.StatusErrorDetails(t, err)
456+
assert.Assert(t, cmp.Len(details.Causes, 2))
457+
458+
for _, cause := range details.Causes {
459+
assert.Equal(t, cause.Field, "spec.instrumentation.logs.retentionPeriod")
460+
}
461+
462+
t.Run("Valid", func(t *testing.T) {
463+
for _, tt := range []string{
464+
"28 weeks",
465+
"90 DAY",
466+
"1 hr",
467+
"PT1D2H",
468+
"1 week 2 days",
469+
} {
470+
u, err := runtime.ToUnstructuredObject(cluster)
471+
assert.NilError(t, err)
472+
assert.NilError(t, unstructured.SetNestedField(u.Object,
473+
tt, "spec", "instrumentation", "logs", "retentionPeriod"))
474+
475+
assert.NilError(t, cc.Create(ctx, u, client.DryRunAll), tt)
476+
}
477+
})
478+
479+
t.Run("Invalid", func(t *testing.T) {
480+
for _, tt := range []string{
481+
// Amount too small
482+
"0 days",
483+
"0",
484+
485+
// Text too long
486+
"2 weeks 3 days 4 hours",
487+
} {
488+
u, err := runtime.ToUnstructuredObject(cluster)
489+
assert.NilError(t, err)
490+
assert.NilError(t, unstructured.SetNestedField(u.Object,
491+
tt, "spec", "instrumentation", "logs", "retentionPeriod"))
492+
493+
err = cc.Create(ctx, u, client.DryRunAll)
494+
assert.Assert(t, apierrors.IsInvalid(err), tt)
495+
assert.ErrorContains(t, err, "retentionPeriod")
496+
}
497+
})
498+
})
499+
}

0 commit comments

Comments
 (0)