Skip to content

Commit

Permalink
connectors: add regression tests
Browse files Browse the repository at this point in the history
This commit adds a collection of randomly generated regression tests to the
connectors chart. Similar to console's tests there are two txtar files.
template-cases.txtar, for hand written test cases, and
template-cases-generated.txtar for cases generated by a fuzzer.

This commit also fixes two small formatting issues in `deployment.yaml` that
were discovered while fuzzing the chart.
  • Loading branch information
chrisseto committed Jul 24, 2024
1 parent 25a04bc commit 4f3c558
Show file tree
Hide file tree
Showing 5 changed files with 24,686 additions and 4 deletions.
115 changes: 115 additions & 0 deletions charts/connectors/chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ package connectors

import (
"encoding/json"
"fmt"
"os"
"regexp"
"slices"
"testing"

fuzz "github.com/google/gofuzz"
"github.com/redpanda-data/helm-charts/pkg/helm"
"github.com/redpanda-data/helm-charts/pkg/testutil"
"github.com/stretchr/testify/require"
"golang.org/x/tools/txtar"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

Expand All @@ -27,3 +37,108 @@ func TestValues(t *testing.T) {

require.JSONEq(t, string(unstructuredValuesJSON), string(typedValuesJSON))
}

func TestTemplate(t *testing.T) {
ctx := testutil.Context(t)
client, err := helm.New(helm.Options{ConfigHome: testutil.TempDir(t)})
require.NoError(t, err)

casesArchive, err := txtar.ParseFile("testdata/template-cases.txtar")
require.NoError(t, err)

generatedCasesArchive, err := txtar.ParseFile("testdata/template-cases-generated.txtar")
require.NoError(t, err)

goldens := testutil.NewTxTar(t, "testdata/template-cases.golden.txtar")

for _, tc := range append(casesArchive.Files, generatedCasesArchive.Files...) {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
var values PartialValues
require.NoError(t, yaml.Unmarshal(tc.Data, &values))

out, err := client.Template(ctx, ".", helm.TemplateOptions{
Name: "console",
Values: values,
Set: []string{
// Tests utilize rng; Can't have that in snapshot testing
// so always disable them.
"test.create=false",
},
})
require.NoError(t, err)
goldens.AssertGolden(t, testutil.YAML, fmt.Sprintf("testdata/%s.yaml.golden", tc.Name), out)
})
}
}

// TestGenerateCases is not a test case (sorry) but a test case generator for
// the console chart.
func TestGenerateCases(t *testing.T) {
// Nasty hack to avoid making a main function somewhere. Sorry not sorry.
if !slices.Contains(os.Args, fmt.Sprintf("-test.run=%s", t.Name())) {
t.Skipf("%s will only run if explicitly specified (-run %q)", t.Name(), t.Name())
}

// Makes strings easier to read.
asciiStrs := func(s *string, c fuzz.Continue) {
const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var x []byte
for i := 0; i < c.Intn(25); i++ {
x = append(x, alphabet[c.Intn(len(alphabet))])
}
*s = string(x)
}
smallInts := func(s *int, c fuzz.Continue) {
*s = c.Intn(501)
}

fuzzer := fuzz.New().NumElements(0, 3).SkipFieldsWithPattern(
regexp.MustCompile("^(SELinuxOptions|WindowsOptions|SeccompProfile|TCPSocket|HTTPHeaders|VolumeSource|Image)$"),
).Funcs(
asciiStrs,
smallInts,
func(t *corev1.ServiceType, c fuzz.Continue) {
types := []corev1.ServiceType{
corev1.ServiceTypeClusterIP,
corev1.ServiceTypeExternalName,
corev1.ServiceTypeNodePort,
corev1.ServiceTypeLoadBalancer,
}
*t = types[c.Intn(len(types))]
},
func(s *corev1.ResourceName, c fuzz.Continue) { asciiStrs((*string)(s), c) },
func(_ *any, c fuzz.Continue) {},
func(_ *[]corev1.ResourceClaim, c fuzz.Continue) {},
func(_ *[]metav1.ManagedFieldsEntry, c fuzz.Continue) {},
)

nilChance := float64(0.8)

files := make([]txtar.File, 0, 50)
for i := 0; i < 50; i++ {
// Every 5 iterations, decrease nil chance to ensure that we're biased
// towards exploring most cases.
if i%5 == 0 && nilChance > .1 {
nilChance -= .1
}

var values PartialValues
fuzzer.NilChance(nilChance).Fuzz(&values)

out, err := yaml.Marshal(values)
require.NoError(t, err)

files = append(files, txtar.File{
Name: fmt.Sprintf("case-%03d", i),
Data: out,
})
}

archive := txtar.Format(&txtar.Archive{
Comment: []byte(fmt.Sprintf(`Generated by %s`, t.Name())),
Files: files,
})

require.NoError(t, os.WriteFile("testdata/template-cases-generated.txtar", archive, 0o644))
}
6 changes: 2 additions & 4 deletions charts/connectors/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,8 @@ spec:
{{- end }}
{{- toYaml .Values.storage.volumeMounts | nindent 12 }}
dnsPolicy: ClusterFirst
restartPolicy: {{ .Values.deployment.restartPolicy }}
{{- with .Values.deployment.schedulerName }}
schedulerName: {{- toYaml . | nindent 8 }}
{{- end }}
restartPolicy: {{ .Values.deployment.restartPolicy | quote }}
schedulerName: {{ .Values.deployment.schedulerName | quote }}
{{- with .Values.deployment.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }}
{{- end }}
Expand Down
Loading

0 comments on commit 4f3c558

Please sign in to comment.