Skip to content

Commit

Permalink
Aligned with function patterns and other patterns
Browse files Browse the repository at this point in the history
Added an option for snaphsot directory
go mod tidy
  • Loading branch information
jguionnet committed Dec 19, 2023
1 parent b8087b1 commit 6ea6eff
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 39 deletions.
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ require (
)

require (
cloud.google.com/go/cloudbuild v1.9.0
github.com/gonvenience/ytbx v1.4.4
github.com/homeport/dyff v1.6.0
cloud.google.com/go/cloudbuild v1.9.0
github.com/slack-go/slack v0.10.3
gotest.tools/v3 v3.0.3
)
Expand Down Expand Up @@ -91,7 +91,6 @@ require (
github.com/gonvenience/term v1.0.2 // indirect
github.com/gonvenience/text v1.0.7 // indirect
github.com/gonvenience/wrap v1.1.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions modules/helm/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ type Options struct {
Logger *logger.Logger // Set a non-default logger that should be used. See the logger package for more info. Use logger.Discard to not print the output while executing the command.
ExtraArgs map[string][]string // Extra arguments to pass to the helm install/upgrade/rollback/delete and helm repo add commands. The key signals the command (e.g., install) while the values are the extra arguments to pass through.
BuildDependencies bool // If true, helm dependencies will be built before rendering template, installing or upgrade the chart.
SnapshotPath string // The path to the snapshot directory when using snapshot based testing. Empty string means use default ($PWD/__snapshot__).
}
81 changes: 52 additions & 29 deletions modules/helm/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/gruntwork-io/terratest/modules/files"
"github.com/gruntwork-io/terratest/modules/testing"

"fmt"
"os"

"github.com/gonvenience/ytbx"
Expand Down Expand Up @@ -145,71 +144,94 @@ func UnmarshalK8SYamlE(t testing.TestingT, yamlData string, destinationObj inter
// It is one of the two functions needed to implement snapshot based testing for helm.
// see https://github.com/gruntwork-io/terratest/issues/1377
// A snapshot is used to compare the current manifests of a chart with the previous manifests.
// A global diff is run against the two snapshost and the number of differences is returned.
func UpdateSnapshot(yamlData string, releaseName string) {
// A global diff is run against the two snapshosts and the number of differences is returned.
func UpdateSnapshot(t testing.TestingT, options *Options, yamlData string, releaseName string) {
require.NoError(t, UpdateSnapshotE(t, options, yamlData, releaseName))
}

// UpdateSnapshot creates or updates the k8s manifest snapshot of a chart (e.g bitnami/nginx).
// It is one of the two functions needed to implement snapshot based testing for helm.
// see https://github.com/gruntwork-io/terratest/issues/1377
// A snapshot is used to compare the current manifests of a chart with the previous manifests.
// A global diff is run against the two snapshosts and the number of differences is returned.
// It will failed the test if there is an error while writing the manifests' snapshot in the file system
func UpdateSnapshotE(t testing.TestingT, options *Options, yamlData string, releaseName string) error {

snapshotDir := "__snapshot__"
var snapshotDir = "__snapshot__"
if options.SnapshotPath != "" {
snapshotDir = options.SnapshotPath
}
// Create a directory if not exists
if !files.FileExists(snapshotDir) {
if err := os.Mkdir(snapshotDir, 0755); err != nil {
fmt.Println("Error creating directory:", err)
return
return errors.WithStackTrace(err)
}
}

filename := snapshotDir + "/" + releaseName + ".yaml"
filename := filepath.Join(snapshotDir, releaseName+".yaml")
// Open a file in write mode
file, err := os.Create(filename)
if err != nil {
fmt.Println("Error creating file:", err)
return
return errors.WithStackTrace(err)
}
defer file.Close()

// Write the k8s manifest into the file
if _, err = file.WriteString(yamlData); err != nil {
fmt.Println("Error writing to file: ", filename, err)
return
return errors.WithStackTrace(err)
}

fmt.Println("k8s manifest written into file: ", filename)
if options.Logger != nil {
options.Logger.Logf(t, "helm chart manifest written into file: %s", filename)
}
return nil
}

// DiffAgainstSnapshot compare the current manifests of a chart (e.g bitnami/nginx)
// with the previous manifests stored in the snapshot.
// see https://github.com/gruntwork-io/terratest/issues/1377
// It returns the number of difference between the two manifest snaphost or -1 in case of error
func DiffAgainstSnapshot(yamlData string, releaseName string) int {
// It will failed the test if there is an error while reading or writing the two manifests in the file system
func DiffAgainstSnapshot(t testing.TestingT, options *Options, yamlData string, releaseName string) int {
numberOfDiffs, err := DiffAgainstSnapshotE(t, options, yamlData, releaseName)
require.NoError(t, err)
return numberOfDiffs
}

// DiffAgainstSnapshotE compare the current manifests of a chart (e.g bitnami/nginx)
// with the previous manifests stored in the snapshot.
// see https://github.com/gruntwork-io/terratest/issues/1377
// It returns the number of difference between the two manifest snaphost or -1 in case of error
func DiffAgainstSnapshotE(t testing.TestingT, options *Options, yamlData string, releaseName string) (int, error) {

snapshotDir := "__snapshot__"
var snapshotDir = "__snapshot__"
if options.SnapshotPath != "" {
snapshotDir = options.SnapshotPath
}

// load the yaml snapshot file
snapshot := snapshotDir + "/" + releaseName + ".yaml"
snapshot := filepath.Join(snapshotDir, releaseName+".yaml")
from, err := ytbx.LoadFile(snapshot)
if err != nil {
fmt.Println("Error opening file:", err)
return -1
return -1, errors.WithStackTrace(err)
}

// write the current manifest into a file as `dyff` does not support string input
currentManifests := releaseName + ".yaml"
file, err := os.Create(currentManifests)
if err != nil {
fmt.Println("Error creating file:", err)
return -1
return -1, errors.WithStackTrace(err)
}

if _, err = file.WriteString(yamlData); err != nil {
fmt.Println("Error writing to file: ", currentManifests, err)
return -1
return -1, errors.WithStackTrace(err)
}
defer file.Close()
defer os.Remove(currentManifests)

to, err := ytbx.LoadFile(currentManifests)
if err != nil {
fmt.Println("Error opening file:", err)
return -1
return -1, errors.WithStackTrace(err)
}

// compare the two manifests using `dyff`
Expand All @@ -218,8 +240,7 @@ func DiffAgainstSnapshot(yamlData string, releaseName string) int {
// create a report
report, err := dyff.CompareInputFiles(from, to, compOpt)
if err != nil {
fmt.Println("Error opening file:", err)
return -1
return -1, errors.WithStackTrace(err)
}

// write any difference to stdout
Expand All @@ -231,8 +252,10 @@ func DiffAgainstSnapshot(yamlData string, releaseName string) int {
UseGoPatchPaths: false,
}

reportWriter.WriteReport(os.Stdout)

// return the number of diffs to use in in assertion while testing: 0 = no differences
return len(reportWriter.Diffs)
err = reportWriter.WriteReport(os.Stdout)
if err != nil {
return -1, errors.WithStackTrace(err)
}
// return the number of diffs to use in assertion while testing: 0 = no differences
return len(reportWriter.Diffs), nil
}
17 changes: 13 additions & 4 deletions modules/helm/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
appsv1 "k8s.io/api/apps/v1"

"github.com/gruntwork-io/terratest/modules/k8s"
"github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/random"
)

Expand All @@ -25,7 +26,7 @@ func TestRemoteChartRender(t *testing.T) {
const (
remoteChartSource = "https://charts.bitnami.com/bitnami"
remoteChartName = "nginx"
remoteChartVersion = "13.2.23"
remoteChartVersion = "13.2.24"
)

t.Parallel()
Expand All @@ -45,6 +46,7 @@ func TestRemoteChartRender(t *testing.T) {
"image.tag": remoteChartVersion,
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since
Expand Down Expand Up @@ -86,6 +88,7 @@ func TestRemoteChartRenderDump(t *testing.T) {
"image.tag": remoteChartVersion,
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since
Expand All @@ -101,15 +104,19 @@ func TestRemoteChartRenderDump(t *testing.T) {
require.Equal(t, namespaceName, deployment.Namespace)

// write chart manifest to a local filesystem directory
UpdateSnapshot(output, releaseName)
options = &Options{
Logger: logger.Default,
SnapshotPath: "__chart_manifests_snapshot__",
}
UpdateSnapshot(t, options, output, releaseName)
}

// Test that we can diff all the manifest to a local snapshot using a remote chart (e.g bitnami/nginx)
func TestRemoteChartRenderDiff(t *testing.T) {
const (
remoteChartSource = "https://charts.bitnami.com/bitnami"
remoteChartName = "nginx"
remoteChartVersion = "13.2.23"
remoteChartVersion = "13.2.24"
// need to set a fix name for the namespace so it is not flag as a difference
namespaceName = "dump-ns"
)
Expand All @@ -122,6 +129,8 @@ func TestRemoteChartRenderDiff(t *testing.T) {
"image.tag": remoteChartVersion,
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
SnapshotPath: "__chart_manifests_snapshot__",
}

// Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since
Expand All @@ -134,5 +143,5 @@ func TestRemoteChartRenderDiff(t *testing.T) {
UnmarshalK8SYaml(t, output, &deployment)

// run the diff and assert there is only one difference: the image name
require.Equal(t, 1, DiffAgainstSnapshot(output, releaseName))
require.Equal(t, 1, DiffAgainstSnapshot(t, options, output, releaseName))
}
12 changes: 8 additions & 4 deletions test/helm_keda_remote_example_template_snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDump(t *testing.T) {
"resources.metricServer.limits.memory": "1234Mi",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand All @@ -68,7 +69,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDump(t *testing.T) {
require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica)

// write chart manifest to a local filesystem directory
helm.UpdateSnapshot(output, releaseName)
helm.UpdateSnapshot(t, options, output, releaseName)
}

// An example of how to verify the rendered template object of a Helm Chart given various inputs.
Expand All @@ -88,6 +89,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDiff(t *testing.T) {
"resources.metricServer.limits.memory": "4321Mi",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand All @@ -111,7 +113,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDiff(t *testing.T) {
require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica)

// run the diff and assert the number of diffs
require.Equal(t, 4, helm.DiffAgainstSnapshot(output, releaseName))
require.Equal(t, 4, helm.DiffAgainstSnapshot(t, options, output, releaseName))
}

// An example of how to store a snapshot of the current manaifest for future comparison
Expand All @@ -131,6 +133,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedPackageDump(t *testing.T) {
"resources.metricServer.limits.memory": "1234Mi",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand All @@ -140,7 +143,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedPackageDump(t *testing.T) {
output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{})

// write chart manifest to a local filesystem directory
helm.UpdateSnapshot(output, releaseName)
helm.UpdateSnapshot(t, options, output, releaseName)
}

// An example of how to verify the current helm k8s manifest against a previous snapshot
Expand All @@ -160,6 +163,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedPackageDiff(t *testing.T) {
"resources.metricServer.limits.memory": "4321Mi",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand All @@ -169,5 +173,5 @@ func TestHelmKedaRemoteExampleTemplateRenderedPackageDiff(t *testing.T) {
output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{})

// run the diff and assert the number of diffs matches the number of diffs in the snapshot
require.Equal(t, 18, helm.DiffAgainstSnapshot(output, releaseName))
require.Equal(t, 18, helm.DiffAgainstSnapshot(t, options, output, releaseName))
}
2 changes: 2 additions & 0 deletions test/helm_keda_remote_example_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeployment(t *testing.T) {
"resources.metricServer.limits.memory": "1234Mi",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand Down Expand Up @@ -87,6 +88,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedValuesFileFixtureDeployment(t *tes
options := &helm.Options{
ValuesFiles: []string{"./fixtures/helm/keda-values.yaml"},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
Logger: logger.Discard,
}

// Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since
Expand Down

0 comments on commit 6ea6eff

Please sign in to comment.