@@ -11,6 +11,11 @@ import (
1111
1212 "github.com/gruntwork-io/terratest/modules/files"
1313 "github.com/gruntwork-io/terratest/modules/testing"
14+
15+ "os"
16+
17+ "github.com/gonvenience/ytbx"
18+ "github.com/homeport/dyff/pkg/dyff"
1419)
1520
1621// RenderTemplate runs `helm template` to render the template given the provided options and returns stdout/stderr from
@@ -134,3 +139,123 @@ func UnmarshalK8SYamlE(t testing.TestingT, yamlData string, destinationObj inter
134139 }
135140 return nil
136141}
142+
143+ // UpdateSnapshot creates or updates the k8s manifest snapshot of a chart (e.g bitnami/nginx).
144+ // It is one of the two functions needed to implement snapshot based testing for helm.
145+ // see https://github.com/gruntwork-io/terratest/issues/1377
146+ // A snapshot is used to compare the current manifests of a chart with the previous manifests.
147+ // A global diff is run against the two snapshosts and the number of differences is returned.
148+ func UpdateSnapshot (t testing.TestingT , options * Options , yamlData string , releaseName string ) {
149+ require .NoError (t , UpdateSnapshotE (t , options , yamlData , releaseName ))
150+ }
151+
152+ // UpdateSnapshotE creates or updates the k8s manifest snapshot of a chart (e.g bitnami/nginx).
153+ // It is one of the two functions needed to implement snapshot based testing for helm.
154+ // see https://github.com/gruntwork-io/terratest/issues/1377
155+ // A snapshot is used to compare the current manifests of a chart with the previous manifests.
156+ // A global diff is run against the two snapshosts and the number of differences is returned.
157+ // It will failed the test if there is an error while writing the manifests' snapshot in the file system
158+ func UpdateSnapshotE (t testing.TestingT , options * Options , yamlData string , releaseName string ) error {
159+
160+ var snapshotDir = "__snapshot__"
161+ if options .SnapshotPath != "" {
162+ snapshotDir = options .SnapshotPath
163+ }
164+ // Create a directory if not exists
165+ if ! files .FileExists (snapshotDir ) {
166+ if err := os .Mkdir (snapshotDir , 0755 ); err != nil {
167+ return errors .WithStackTrace (err )
168+ }
169+ }
170+
171+ filename := filepath .Join (snapshotDir , releaseName + ".yaml" )
172+ // Open a file in write mode
173+ file , err := os .Create (filename )
174+ if err != nil {
175+ return errors .WithStackTrace (err )
176+ }
177+ defer file .Close ()
178+
179+ // Write the k8s manifest into the file
180+ if _ , err = file .WriteString (yamlData ); err != nil {
181+ return errors .WithStackTrace (err )
182+ }
183+
184+ if options .Logger != nil {
185+ options .Logger .Logf (t , "helm chart manifest written into file: %s" , filename )
186+ }
187+ return nil
188+ }
189+
190+ // DiffAgainstSnapshot compare the current manifests of a chart (e.g bitnami/nginx)
191+ // with the previous manifests stored in the snapshot.
192+ // see https://github.com/gruntwork-io/terratest/issues/1377
193+ // It returns the number of difference between the two manifests or -1 in case of error
194+ // It will fail the test if there is an error while reading or writing the two manifests in the file system
195+ func DiffAgainstSnapshot (t testing.TestingT , options * Options , yamlData string , releaseName string ) int {
196+ numberOfDiffs , err := DiffAgainstSnapshotE (t , options , yamlData , releaseName )
197+ require .NoError (t , err )
198+ return numberOfDiffs
199+ }
200+
201+ // DiffAgainstSnapshotE compare the current manifests of a chart (e.g bitnami/nginx)
202+ // with the previous manifests stored in the snapshot.
203+ // see https://github.com/gruntwork-io/terratest/issues/1377
204+ // It returns the number of difference between the manifests or -1 in case of error
205+ func DiffAgainstSnapshotE (t testing.TestingT , options * Options , yamlData string , releaseName string ) (int , error ) {
206+
207+ var snapshotDir = "__snapshot__"
208+ if options .SnapshotPath != "" {
209+ snapshotDir = options .SnapshotPath
210+ }
211+
212+ // load the yaml snapshot file
213+ snapshot := filepath .Join (snapshotDir , releaseName + ".yaml" )
214+ from , err := ytbx .LoadFile (snapshot )
215+ if err != nil {
216+ return - 1 , errors .WithStackTrace (err )
217+ }
218+
219+ // write the current manifest into a file as `dyff` does not support string input
220+ currentManifests := releaseName + ".yaml"
221+ file , err := os .Create (currentManifests )
222+ if err != nil {
223+ return - 1 , errors .WithStackTrace (err )
224+ }
225+
226+ if _ , err = file .WriteString (yamlData ); err != nil {
227+ return - 1 , errors .WithStackTrace (err )
228+ }
229+ defer file .Close ()
230+ defer os .Remove (currentManifests )
231+
232+ to , err := ytbx .LoadFile (currentManifests )
233+ if err != nil {
234+ return - 1 , errors .WithStackTrace (err )
235+ }
236+
237+ // compare the two manifests using `dyff`
238+ compOpt := dyff .KubernetesEntityDetection (false )
239+
240+ // create a report
241+ report , err := dyff .CompareInputFiles (from , to , compOpt )
242+ if err != nil {
243+ return - 1 , errors .WithStackTrace (err )
244+ }
245+
246+ // write any difference to stdout
247+ reportWriter := & dyff.HumanReport {
248+ Report : report ,
249+ DoNotInspectCerts : false ,
250+ NoTableStyle : false ,
251+ OmitHeader : false ,
252+ UseGoPatchPaths : false ,
253+ }
254+
255+ err = reportWriter .WriteReport (os .Stdout )
256+ if err != nil {
257+ return - 1 , errors .WithStackTrace (err )
258+ }
259+ // return the number of diffs to use in assertion while testing: 0 = no differences
260+ return len (reportWriter .Diffs ), nil
261+ }
0 commit comments