Repository: redhat-openshift-ecosystem/openshift-preflight
Pull request #251 (2021-09-13 20:35:21)

Add unit tests


Patch:
diff --git a/certification/formatters/generic.go b/certification/formatters/generic.go
index 89dc44c..781b860 100644
--- a/certification/formatters/generic.go
+++ b/certification/formatters/generic.go
@@ -9,11 +9,16 @@ import (
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/runtime"
 )
 
+var (
+	jsonMarshalIndent = json.MarshalIndent
+	xmlMarshalIndent  = xml.MarshalIndent
+)
+
 // genericJSONFormatter is a FormatterFunc that formats results as JSON
 func genericJSONFormatter(r runtime.Results) ([]byte, error) {
 	response := getResponse(r)
 
-	responseJSON, err := json.MarshalIndent(response, "", "    ")
+	responseJSON, err := jsonMarshalIndent(response, "", "    ")
 	if err != nil {
 		e := fmt.Errorf("%w with formatter %s: %s",
 			errors.ErrFormattingResults,
@@ -31,7 +36,7 @@ func genericJSONFormatter(r runtime.Results) ([]byte, error) {
 func genericXMLFormatter(r runtime.Results) ([]byte, error) {
 	response := getResponse(r)
 
-	responseJSON, err := xml.MarshalIndent(response, "", "    ")
+	responseJSON, err := xmlMarshalIndent(response, "", "    ")
 	if err != nil {
 		e := fmt.Errorf("%w with formatter %s: %s",
 			errors.ErrFormattingResults,
diff --git a/go.mod b/go.mod
index a63a1a7..b9a5d3d 100644
--- a/go.mod
+++ b/go.mod
@@ -25,6 +25,7 @@ require (
 	golang.org/x/text v0.3.7 // indirect
 	gopkg.in/ini.v1 v1.63.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0
+	gotest.tools/v3 v3.0.3 // indirect
 	k8s.io/api v0.22.1
 	k8s.io/apimachinery v0.22.1
 	k8s.io/client-go v0.22.1


Test patch:
diff --git a/certification/formatters/formatters_test.go b/certification/formatters/formatters_test.go
index d468ef6..1d81417 100644
--- a/certification/formatters/formatters_test.go
+++ b/certification/formatters/formatters_test.go
@@ -1,8 +1,11 @@
 package formatters
 
 import (
+	"fmt"
+
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/errors"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/runtime"
 )
 
@@ -35,6 +38,21 @@ var _ = Describe("Formatters", func() {
 	})
 
 	Describe("When creating a new generic formatter", func() {
+
+		Context("with improper arguments", func() {
+			expectedResult := []byte(fmt.Errorf("failed to create a new generic formatter: %w",
+				errors.ErrFormatterNameNotProvided).Error())
+			var fn FormatterFunc = func(runtime.Results) ([]byte, error) {
+				return expectedResult, nil
+			}
+
+			emptyNameFormatter, err := New("", "txt", fn)
+			It("should return an error because of an empty name", func() {
+				Expect(err).To(HaveOccurred())
+				Expect(emptyNameFormatter).To(BeNil())
+			})
+		})
+
 		Context("with proper arguments", func() {
 			var expectedResult []byte = []byte("this is a test")
 			var name string = "testFormatter"
diff --git a/certification/formatters/generic_test.go b/certification/formatters/generic_test.go
new file mode 100644
index 0000000..f26dded
--- /dev/null
+++ b/certification/formatters/generic_test.go
@@ -0,0 +1,168 @@
+package formatters
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"errors"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
+	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/runtime"
+	"gotest.tools/v3/assert"
+)
+
+func TestGenericJSONFormatter(t *testing.T) {
+	generateTestResults := func(image string, passed bool) runtime.Results {
+		return runtime.Results{
+			TestedImage:   image,
+			PassedOverall: passed,
+			Passed: []runtime.Result{
+				{
+					Check:       certification.NewGenericCheck("passed1", nil, certification.Metadata{}, certification.HelpText{}),
+					ElapsedTime: time.Duration(1000 * time.Millisecond),
+				},
+			},
+			Failed: []runtime.Result{
+				{
+					Check:       certification.NewGenericCheck("failed1", nil, certification.Metadata{}, certification.HelpText{}),
+					ElapsedTime: time.Duration(1001 * time.Millisecond),
+				},
+			},
+		}
+	}
+
+	testCases := []struct {
+		results              runtime.Results
+		marshalIndentFailure bool
+		expectedErrString    string
+	}{
+		{
+			results:              generateTestResults("image1", true),
+			marshalIndentFailure: false,
+		},
+		{
+			results:              generateTestResults("image2", false),
+			marshalIndentFailure: false,
+		},
+		{
+			results:              generateTestResults("image3", true),
+			marshalIndentFailure: true, // failure to json.MarshalIndent
+			expectedErrString:    "this is an error",
+		},
+	}
+
+	for _, tc := range testCases {
+
+		// Patch the function if we expect an error
+		if tc.marshalIndentFailure {
+			jsonMarshalIndent = func(v interface{}, prefix, indent string) ([]byte, error) {
+				return nil, errors.New("this is an error")
+			}
+		} else {
+			jsonMarshalIndent = json.MarshalIndent
+		}
+
+		// Run the function
+		funcOutput, err := genericJSONFormatter(tc.results)
+
+		if err == nil {
+			// Marshal the response JSON back into an object
+			var testResponseObj UserResponse
+			assert.NilError(t, json.Unmarshal(funcOutput, &testResponseObj))
+
+			// Assertions
+			assert.Equal(t, tc.results.TestedImage, testResponseObj.Image)
+			assert.Equal(t, tc.results.PassedOverall, testResponseObj.Passed)
+
+			for index, i := range tc.results.Passed {
+				assert.Equal(t, i.Name(), testResponseObj.Results.Passed[index].Name)
+				assert.Equal(t, float64(i.ElapsedTime/time.Millisecond), testResponseObj.Results.Passed[index].ElapsedTime)
+			}
+			for index, i := range tc.results.Failed {
+				assert.Equal(t, i.Name(), testResponseObj.Results.Failed[index].Name)
+				assert.Equal(t, float64(i.ElapsedTime/time.Millisecond), testResponseObj.Results.Failed[index].ElapsedTime)
+			}
+		} else {
+			assert.Equal(t, true, strings.Contains(err.Error(), tc.expectedErrString))
+		}
+	}
+}
+
+func TestGenericXMLFormatter(t *testing.T) {
+	generateTestResults := func(image string, passed bool) runtime.Results {
+		return runtime.Results{
+			TestedImage:   image,
+			PassedOverall: passed,
+			Passed: []runtime.Result{
+				{
+					Check:       certification.NewGenericCheck("passed1", nil, certification.Metadata{}, certification.HelpText{}),
+					ElapsedTime: time.Duration(1000 * time.Millisecond),
+				},
+			},
+			Failed: []runtime.Result{
+				{
+					Check:       certification.NewGenericCheck("failed1", nil, certification.Metadata{}, certification.HelpText{}),
+					ElapsedTime: time.Duration(1001 * time.Millisecond),
+				},
+			},
+		}
+	}
+
+	testCases := []struct {
+		results              runtime.Results
+		marshalIndentFailure bool
+		expectedErrString    string
+	}{
+		{
+			results:              generateTestResults("image1", true),
+			marshalIndentFailure: false,
+		},
+		{
+			results:              generateTestResults("image2", false),
+			marshalIndentFailure: false,
+		},
+		{
+			results:              generateTestResults("image3", true),
+			marshalIndentFailure: true, // failure to xml.MarshalIndent
+			expectedErrString:    "this is an error",
+		},
+	}
+
+	for _, tc := range testCases {
+
+		// Patch the function if we expect an error
+		if tc.marshalIndentFailure {
+			xmlMarshalIndent = func(v interface{}, prefix, indent string) ([]byte, error) {
+				return nil, errors.New("this is an error")
+			}
+		} else {
+			xmlMarshalIndent = xml.MarshalIndent
+		}
+
+		// Run the function
+		funcOutput, err := genericXMLFormatter(tc.results)
+
+		if err == nil {
+			// Marshal the response XML back into an object
+			var testResponseObj UserResponse
+			assert.NilError(t, xml.Unmarshal(funcOutput, &testResponseObj))
+
+			// Assertions
+			assert.Equal(t, tc.results.TestedImage, testResponseObj.Image)
+			assert.Equal(t, tc.results.PassedOverall, testResponseObj.Passed)
+
+			for index, i := range tc.results.Passed {
+				assert.Equal(t, i.Name(), testResponseObj.Results.Passed[index].Name)
+				assert.Equal(t, float64(i.ElapsedTime/time.Millisecond), testResponseObj.Results.Passed[index].ElapsedTime)
+			}
+			for index, i := range tc.results.Failed {
+				assert.Equal(t, i.Name(), testResponseObj.Results.Failed[index].Name)
+				assert.Equal(t, float64(i.ElapsedTime/time.Millisecond), testResponseObj.Results.Failed[index].ElapsedTime)
+			}
+		} else {
+			assert.Equal(t, true, strings.Contains(err.Error(), tc.expectedErrString))
+		}
+	}
+}