From 0cf057b671490fe1ed55132c65bf9be7c07ac748 Mon Sep 17 00:00:00 2001 From: Brandon Palm Date: Thu, 25 Jan 2024 07:34:39 -0600 Subject: [PATCH] Add unit tests for testhelper package (#1835) --- pkg/provider/filters.go | 35 + pkg/provider/scale_object_test.go | 50 ++ pkg/testhelper/testhelper.go | 61 ++ pkg/testhelper/testhelper_test.go | 1067 +++++++++++++++++++++++++++++ 4 files changed, 1213 insertions(+) diff --git a/pkg/provider/filters.go b/pkg/provider/filters.go index 43cbc3e11..22b2d9166 100644 --- a/pkg/provider/filters.go +++ b/pkg/provider/filters.go @@ -24,6 +24,9 @@ import ( "github.com/test-network-function/cnf-certification-test/internal/log" ) +// GetGuaranteedPodsWithExclusiveCPUs returns a slice of Pod objects that are guaranteed to have exclusive CPUs. +// It iterates over the Pods in the TestEnvironment and filters out the Pods that do not have exclusive CPUs. +// The filtered Pods are then returned as a slice. func (env *TestEnvironment) GetGuaranteedPodsWithExclusiveCPUs() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -34,6 +37,8 @@ func (env *TestEnvironment) GetGuaranteedPodsWithExclusiveCPUs() []*Pod { return filteredPods } +// GetGuaranteedPodsWithIsolatedCPUs returns a list of pods from the TestEnvironment +// that are guaranteed to have isolated CPUs and are CPU isolation compliant. func (env *TestEnvironment) GetGuaranteedPodsWithIsolatedCPUs() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -44,6 +49,10 @@ func (env *TestEnvironment) GetGuaranteedPodsWithIsolatedCPUs() []*Pod { return filteredPods } +// GetGuaranteedPods returns a slice of guaranteed pods in the test environment. +// A guaranteed pod is a pod that meets certain criteria specified by the IsPodGuaranteed method. +// The method iterates over all pods in the environment and filters out the guaranteed ones. +// It returns the filtered pods as a slice. func (env *TestEnvironment) GetGuaranteedPods() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -54,6 +63,7 @@ func (env *TestEnvironment) GetGuaranteedPods() []*Pod { return filteredPods } +// GetNonGuaranteedPods returns a slice of non-guaranteed pods in the test environment. func (env *TestEnvironment) GetNonGuaranteedPods() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -64,6 +74,9 @@ func (env *TestEnvironment) GetNonGuaranteedPods() []*Pod { return filteredPods } +// GetPodsWithoutAffinityRequiredLabel returns a slice of Pod objects that do not have the affinity required label. +// It iterates over the Pods in the TestEnvironment and filters out the ones that do not have the affinity required label. +// The filtered Pods are returned as a slice. func (env *TestEnvironment) GetPodsWithoutAffinityRequiredLabel() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -74,6 +87,9 @@ func (env *TestEnvironment) GetPodsWithoutAffinityRequiredLabel() []*Pod { return filteredPods } +// GetAffinityRequiredPods returns a slice of Pod objects that have affinity required. +// It iterates over the Pods in the TestEnvironment and filters out the Pods that have affinity required. +// The filtered Pods are returned as a slice. func (env *TestEnvironment) GetAffinityRequiredPods() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -84,6 +100,9 @@ func (env *TestEnvironment) GetAffinityRequiredPods() []*Pod { return filteredPods } +// GetHugepagesPods returns a slice of Pod objects that have hugepages enabled. +// It iterates over the Pods in the TestEnvironment and filters out the ones that do not have hugepages. +// The filtered Pods are returned as a []*Pod. func (env *TestEnvironment) GetHugepagesPods() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -94,6 +113,7 @@ func (env *TestEnvironment) GetHugepagesPods() []*Pod { return filteredPods } +// GetCPUPinningPodsWithDpdk returns a slice of Pods that have CPU pinning enabled with DPDK. func (env *TestEnvironment) GetCPUPinningPodsWithDpdk() []*Pod { return filterDPDKRunningPods(env.GetGuaranteedPodsWithExclusiveCPUs()) } @@ -135,6 +155,9 @@ func filterDPDKRunningPods(pods []*Pod) []*Pod { return filteredPods } +// GetShareProcessNamespacePods returns a slice of Pod objects that have the ShareProcessNamespace flag set to true. +// It iterates over the Pods in the TestEnvironment and filters out the ones that do not have the ShareProcessNamespace flag set. +// The filtered Pods are then returned as a slice. func (env *TestEnvironment) GetShareProcessNamespacePods() []*Pod { var filteredPods []*Pod for _, p := range env.Pods { @@ -145,6 +168,10 @@ func (env *TestEnvironment) GetShareProcessNamespacePods() []*Pod { return filteredPods } +// GetPodsUsingSRIOV returns a list of pods that are using SR-IOV. +// It iterates through the pods in the TestEnvironment and checks if each pod is using SR-IOV. +// If an error occurs while checking the SR-IOV usage for a pod, it returns an error. +// The filtered pods that are using SR-IOV are returned along with a nil error. func (env *TestEnvironment) GetPodsUsingSRIOV() ([]*Pod, error) { var filteredPods []*Pod for _, p := range env.Pods { @@ -169,18 +196,26 @@ func getContainers(pods []*Pod) []*Container { return containers } +// GetGuaranteedPodContainersWithExclusiveCPUs returns a slice of Container objects representing the containers +// that have exclusive CPUs in the TestEnvironment. func (env *TestEnvironment) GetGuaranteedPodContainersWithExclusiveCPUs() []*Container { return getContainers(env.GetGuaranteedPodsWithExclusiveCPUs()) } +// GetNonGuaranteedPodContainersWithoutHostPID returns a slice of containers from the test environment +// that belong to non-guaranteed pods without the HostPID setting enabled. func (env *TestEnvironment) GetNonGuaranteedPodContainersWithoutHostPID() []*Container { return getContainers(filterPodsWithoutHostPID(env.GetNonGuaranteedPods())) } +// GetGuaranteedPodContainersWithExclusiveCPUsWithoutHostPID returns a slice of containers from the test environment +// that belong to pods with exclusive CPUs and do not have the host PID enabled. func (env *TestEnvironment) GetGuaranteedPodContainersWithExclusiveCPUsWithoutHostPID() []*Container { return getContainers(filterPodsWithoutHostPID(env.GetGuaranteedPodsWithExclusiveCPUs())) } +// GetGuaranteedPodContainersWithIsolatedCPUsWithoutHostPID returns a slice of containers from the TestEnvironment +// that have guaranteed pods with isolated CPUs and without the HostPID flag set. func (env *TestEnvironment) GetGuaranteedPodContainersWithIsolatedCPUsWithoutHostPID() []*Container { return getContainers(filterPodsWithoutHostPID(env.GetGuaranteedPodsWithIsolatedCPUs())) } diff --git a/pkg/provider/scale_object_test.go b/pkg/provider/scale_object_test.go index 7aad9ee0f..c21f499c8 100644 --- a/pkg/provider/scale_object_test.go +++ b/pkg/provider/scale_object_test.go @@ -40,3 +40,53 @@ func TestCrScale_ToString(t *testing.T) { }) } } + +func TestIsScaleObjectReady(t *testing.T) { + type fields struct { + Scale *scalingv1.Scale + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "test1", + fields: fields{ + Scale: &scalingv1.Scale{ + Spec: scalingv1.ScaleSpec{ + Replicas: 2, + }, + Status: scalingv1.ScaleStatus{ + Replicas: 2, + }, + }, + }, + want: true, + }, + { + name: "test2", + fields: fields{ + Scale: &scalingv1.Scale{ + Spec: scalingv1.ScaleSpec{ + Replicas: 2, + }, + Status: scalingv1.ScaleStatus{ + Replicas: 3, + }, + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + crScale := CrScale{ + Scale: tt.fields.Scale, + } + if got := crScale.IsScaleObjectReady(); got != tt.want { + t.Errorf("CrScale.IsScaleObjectReady() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/testhelper/testhelper.go b/pkg/testhelper/testhelper.go index 81a68067d..3b3d03061 100644 --- a/pkg/testhelper/testhelper.go +++ b/pkg/testhelper/testhelper.go @@ -59,6 +59,7 @@ func Equal(p, other []*ReportObject) bool { return true } +// FailureReasonOutTestString returns a string representation of the FailureReasonOut struct. func FailureReasonOutTestString(p FailureReasonOut) (out string) { out = "testhelper.FailureReasonOut{" out += fmt.Sprintf("CompliantObjectsOut: %s,", ReportObjectTestStringPointer(p.CompliantObjectsOut)) @@ -67,6 +68,8 @@ func FailureReasonOutTestString(p FailureReasonOut) (out string) { return out } +// ReportObjectTestStringPointer takes a slice of pointers to ReportObject and returns a string representation of the objects. +// The returned string is in the format "[]*testhelper.ReportObject{&{...}, &{...}, ...}". func ReportObjectTestStringPointer(p []*ReportObject) (out string) { out = "[]*testhelper.ReportObject{" for _, p := range p { @@ -76,6 +79,9 @@ func ReportObjectTestStringPointer(p []*ReportObject) (out string) { return out } +// ReportObjectTestString returns a string representation of the given slice of ReportObject. +// Each ReportObject is formatted using the %#v format specifier and appended to the output string. +// The resulting string is enclosed in square brackets and prefixed with "[]testhelper.ReportObject{". func ReportObjectTestString(p []*ReportObject) (out string) { out = "[]testhelper.ReportObject{" for _, p := range p { @@ -85,6 +91,9 @@ func ReportObjectTestString(p []*ReportObject) (out string) { return out } +// Equal checks if the current FailureReasonOut is equal to the other FailureReasonOut. +// It compares the CompliantObjectsOut and NonCompliantObjectsOut fields of both structs. +// Returns true if they are equal, false otherwise. func (p FailureReasonOut) Equal(other FailureReasonOut) bool { return Equal(p.CompliantObjectsOut, other.CompliantObjectsOut) && Equal(p.NonCompliantObjectsOut, other.NonCompliantObjectsOut) @@ -204,6 +213,10 @@ const ( PodRoleBinding = "Pods with RoleBindings details" ) +// SetContainerProcessValues sets the values for a container process in the report object. +// It takes the scheduling policy, scheduling priority, and command line as input parameters. +// It adds the process command line, scheduling policy, and scheduling priority fields to the report object. +// Finally, it sets the object type to ContainerProcessType. func (obj *ReportObject) SetContainerProcessValues(aPolicy, aPriority, aCommandLine string) *ReportObject { obj.AddField(ProcessCommandLine, aCommandLine) obj.AddField(SchedulingPolicy, aPolicy) @@ -212,6 +225,9 @@ func (obj *ReportObject) SetContainerProcessValues(aPolicy, aPriority, aCommandL return obj } +// NewContainerReportObject creates a new ReportObject for a container. +// It takes the namespace, pod name, container name, reason, and compliance status as parameters. +// It returns a pointer to the created ReportObject. func NewContainerReportObject(aNamespace, aPodName, aContainerName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, ContainerType, isCompliant) out.AddField(Namespace, aNamespace) @@ -220,6 +236,9 @@ func NewContainerReportObject(aNamespace, aPodName, aContainerName, aReason stri return out } +// NewCertifiedContainerReportObject creates a new ReportObject for a certified container. +// It takes a ContainerImageIdentifier, aReason string, and a boolean indicating whether the container is compliant. +// It returns a pointer to the created ReportObject. func NewCertifiedContainerReportObject(cii provider.ContainerImageIdentifier, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, ContainerImageType, isCompliant) out.AddField(ImageDigest, cii.Digest) @@ -229,18 +248,24 @@ func NewCertifiedContainerReportObject(cii provider.ContainerImageIdentifier, aR return out } +// NewNodeReportObject creates a new ReportObject for a node with the given name, reason, and compliance status. +// It returns the created ReportObject. func NewNodeReportObject(aNodeName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, NodeType, isCompliant) out.AddField(Name, aNodeName) return out } +// NewClusterVersionReportObject creates a new ReportObject for a cluster version. +// It takes the version, aReason, and isCompliant as input parameters and returns the created ReportObject. func NewClusterVersionReportObject(version, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, OCPClusterType, isCompliant) out.AddField(OCPClusterVersionType, version) return out } +// NewTaintReportObject creates a new ReportObject with taint-related information. +// It takes in the taintBit, nodeName, aReason, and isCompliant parameters and returns a pointer to the created ReportObject. func NewTaintReportObject(taintBit, nodeName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, TaintType, isCompliant) out.AddField(NodeType, nodeName) @@ -248,6 +273,9 @@ func NewTaintReportObject(taintBit, nodeName, aReason string, isCompliant bool) return out } +// NewPodReportObject creates a new ReportObject for a pod. +// It takes the namespace, pod name, reason, and compliance status as input parameters. +// It returns a pointer to the created ReportObject. func NewPodReportObject(aNamespace, aPodName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, PodType, isCompliant) out.AddField(Namespace, aNamespace) @@ -255,6 +283,9 @@ func NewPodReportObject(aNamespace, aPodName, aReason string, isCompliant bool) return out } +// NewHelmChartReportObject creates a new ReportObject for a Helm chart. +// It takes the namespace, Helm chart name, reason, and compliance status as input parameters. +// It returns the created ReportObject. func NewHelmChartReportObject(aNamespace, aHelmChartName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, HelmType, isCompliant) out.AddField(Namespace, aNamespace) @@ -262,6 +293,9 @@ func NewHelmChartReportObject(aNamespace, aHelmChartName, aReason string, isComp return out } +// NewOperatorReportObject creates a new ReportObject for an operator. +// It takes the namespace, operator name, reason, and compliance status as input parameters. +// It returns the created ReportObject. func NewOperatorReportObject(aNamespace, aOperatorName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, OperatorType, isCompliant) out.AddField(Namespace, aNamespace) @@ -269,6 +303,9 @@ func NewOperatorReportObject(aNamespace, aOperatorName, aReason string, isCompli return out } +// NewDeploymentReportObject creates a new ReportObject for a deployment. +// It takes the namespace, deployment name, reason, and compliance status as input parameters. +// It returns a pointer to the created ReportObject. func NewDeploymentReportObject(aNamespace, aDeploymentName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, DeploymentType, isCompliant) out.AddField(Namespace, aNamespace) @@ -276,6 +313,9 @@ func NewDeploymentReportObject(aNamespace, aDeploymentName, aReason string, isCo return out } +// NewStatefulSetReportObject creates a new ReportObject for a StatefulSet. +// It takes the namespace, statefulSetName, reason, and compliance status as parameters. +// It returns the created ReportObject. func NewStatefulSetReportObject(aNamespace, aStatefulSetName, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, StatefulSetType, isCompliant) out.AddField(Namespace, aNamespace) @@ -283,6 +323,8 @@ func NewStatefulSetReportObject(aNamespace, aStatefulSetName, aReason string, is return out } +// NewCrdReportObject creates a new ReportObject for a custom resource definition (CRD). +// It takes the name, version, reason, and compliance status as parameters and returns the created ReportObject. func NewCrdReportObject(aName, aVersion, aReason string, isCompliant bool) (out *ReportObject) { out = NewReportObject(aReason, CustomResourceDefinitionType, isCompliant) out.AddField(CustomResourceDefinitionName, aName) @@ -290,6 +332,10 @@ func NewCrdReportObject(aName, aVersion, aReason string, isCompliant bool) (out return out } +// NewReportObject creates a new ReportObject with the specified reason, type, and compliance status. +// If isCompliant is true, the reason is added as a field with the key ReasonForCompliance. +// If isCompliant is false, the reason is added as a field with the key ReasonForNonCompliance. +// Returns a pointer to the created ReportObject. func NewReportObject(aReason, aType string, isCompliant bool) (out *ReportObject) { out = &ReportObject{} out.ObjectType = aType @@ -301,25 +347,40 @@ func NewReportObject(aReason, aType string, isCompliant bool) (out *ReportObject return out } +// AddField adds a key-value pair to the ReportObject. +// It appends the given key to the ObjectFieldsKeys slice and the given value to the ObjectFieldsValues slice. +// It returns the modified ReportObject. func (obj *ReportObject) AddField(aKey, aValue string) (out *ReportObject) { obj.ObjectFieldsKeys = append(obj.ObjectFieldsKeys, aKey) obj.ObjectFieldsValues = append(obj.ObjectFieldsValues, aValue) return obj } +// NewNamespacedReportObject creates a new ReportObject with the specified reason, type, compliance status, and namespace. +// It adds the namespace field to the ReportObject. func NewNamespacedReportObject(aReason, aType string, isCompliant bool, aNamespace string) (out *ReportObject) { return NewReportObject(aReason, aType, isCompliant).AddField(Namespace, aNamespace) } +// NewNamespacedNamedReportObject creates a new namespaced named report object with the given parameters. +// It returns a pointer to the created ReportObject. +// The report object contains the specified reason, type, compliance status, namespace, and name. func NewNamespacedNamedReportObject(aReason, aType string, isCompliant bool, aNamespace, aName string) (out *ReportObject) { return NewReportObject(aReason, aType, isCompliant).AddField(Namespace, aNamespace).AddField(Name, aName) } +// SetType sets the type of the ReportObject. +// It takes aType as a parameter and updates the ObjectType field of the ReportObject. +// It returns a pointer to the updated ReportObject. func (obj *ReportObject) SetType(aType string) (out *ReportObject) { obj.ObjectType = aType return obj } +// ResultToString converts an integer result code into a corresponding string representation. +// It takes an integer result as input and returns the corresponding string representation. +// The possible result codes are SUCCESS, FAILURE, and ERROR. +// If the input result code is not recognized, an empty string is returned. func ResultToString(result int) (str string) { switch result { case SUCCESS: diff --git a/pkg/testhelper/testhelper_test.go b/pkg/testhelper/testhelper_test.go index adadc8780..7c7ddc017 100644 --- a/pkg/testhelper/testhelper_test.go +++ b/pkg/testhelper/testhelper_test.go @@ -20,8 +20,457 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/test-network-function/cnf-certification-test/pkg/provider" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + storagev1 "k8s.io/api/storage/v1" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func TestNewContainerReportObject(t *testing.T) { + testCases := []struct { + testNamespace string + testPodName string + testContainerName string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testNamespace: "testNamespace", + testPodName: "testPodName", + testContainerName: "testContainerName", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: "Container", + ObjectFieldsKeys: []string{ + Namespace, + PodName, + ContainerName, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testNamespace", + "testPodName", + "testContainerName", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewContainerReportObject(testCase.testNamespace, testCase.testPodName, testCase.testContainerName, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewCertifiedContainerReportObject(t *testing.T) { + reportObj := NewCertifiedContainerReportObject(provider.ContainerImageIdentifier{ + Registry: "testRegistry", + Repository: "testRepository", + Tag: "testTag", + Digest: "testDigest", + }, "testReason", true) + + assert.Equal(t, ContainerImageType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, []string{ImageRegistry, ImageRepo, ImageTag, ImageDigest, ReasonForCompliance}, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, []string{"testRegistry", "testRepository", "testTag", "testDigest", "testReason"}, reportValue) + } +} + +func TestNewNodeReportObject(t *testing.T) { + testCases := []struct { + testNodeName string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testNodeName: "testNodeName", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: NodeType, + ObjectFieldsKeys: []string{ + Name, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testNodeName", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewNodeReportObject(testCase.testNodeName, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewClusterVersionReportObject(t *testing.T) { + testCases := []struct { + testVersion string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testVersion: "testVersion", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: OCPClusterType, + ObjectFieldsKeys: []string{ + OCPClusterVersionType, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testVersion", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewClusterVersionReportObject(testCase.testVersion, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewPodReportObject(t *testing.T) { + testCases := []struct { + testNamespace string + testPodName string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testNamespace: "testNamespace", + testPodName: "testPodName", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: PodType, + ObjectFieldsKeys: []string{ + Namespace, + PodName, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testNamespace", + "testPodName", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewPodReportObject(testCase.testNamespace, testCase.testPodName, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewTaintReportObject(t *testing.T) { + testCases := []struct { + testTaint string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testTaint: "testTaint", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: TaintType, + ObjectFieldsKeys: []string{ + NodeType, + ReasonForCompliance, + TaintBit, + }, + ObjectFieldsValues: []string{ + "node1", + "testTaint", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewTaintReportObject(testCase.testTaint, "node1", testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewHelmChartReportObject(t *testing.T) { + testCases := []struct { + testChart string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testChart: "testChart", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: HelmType, + ObjectFieldsKeys: []string{ + Name, + Namespace, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testChart", + "testReason", + "helm1", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewHelmChartReportObject(testCase.testChart, "helm1", testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewOperatorReportObject(t *testing.T) { + testCases := []struct { + testOperator string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testOperator: "testOperator", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: OperatorType, + ObjectFieldsKeys: []string{ + Name, + Namespace, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testOperator", + "testReason", + "operator1", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewOperatorReportObject(testCase.testOperator, "operator1", testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewDeploymentReportObject(t *testing.T) { + testCases := []struct { + testNamespace string + testDeployment string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testNamespace: "testNamespace", + testDeployment: "testDeployment", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: DeploymentType, + ObjectFieldsKeys: []string{ + Namespace, + DeploymentName, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testNamespace", + "testDeployment", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewDeploymentReportObject(testCase.testNamespace, testCase.testDeployment, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewStatefulSetReportObject(t *testing.T) { + testCases := []struct { + testNamespace string + testStatefulSet string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testNamespace: "testNamespace", + testStatefulSet: "testStatefulSet", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: StatefulSetType, + ObjectFieldsKeys: []string{ + Namespace, + StatefulSetName, + ReasonForCompliance, + }, + ObjectFieldsValues: []string{ + "testNamespace", + "testStatefulSet", + "testReason", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewStatefulSetReportObject(testCase.testNamespace, testCase.testStatefulSet, testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestNewCrdReportObject(t *testing.T) { + testCases := []struct { + testCrd string + testReason string + testIsCompliant bool + expectedOutput *ReportObject + }{ + { + testCrd: "testCrd", + testReason: "testReason", + testIsCompliant: true, + expectedOutput: &ReportObject{ + ObjectType: CustomResourceDefinitionType, + ObjectFieldsKeys: []string{ + CustomResourceDefinitionName, + ReasonForCompliance, + CustomResourceDefinitionVersion, + }, + ObjectFieldsValues: []string{ + "testCrd", + "testReason", + "version1", + }, + }, + }, + } + + for _, testCase := range testCases { + reportObj := NewCrdReportObject(testCase.testCrd, "version1", testCase.testReason, testCase.testIsCompliant) + + assert.Equal(t, testCase.expectedOutput.ObjectType, reportObj.ObjectType) + for _, reportKey := range reportObj.ObjectFieldsKeys { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsKeys, reportKey) + } + + for _, reportValue := range reportObj.ObjectFieldsValues { + assert.Contains(t, testCase.expectedOutput.ObjectFieldsValues, reportValue) + } + } +} + +func TestSetContainerProcessValues(t *testing.T) { + reportObj := NewContainerReportObject("namespace1", "pod1", "container1", "reason1", true) + reportObj.SetContainerProcessValues("policy1", "priority1", "command1") + assert.Equal(t, ContainerProcessType, reportObj.ObjectType) +} + func TestResultToString(t *testing.T) { testCases := []struct { input int @@ -37,3 +486,621 @@ func TestResultToString(t *testing.T) { assert.Equal(t, tc.expectedResult, ResultToString(tc.input)) } } + +func TestEqual(t *testing.T) { + testCases := []struct { + testSlice1 []*ReportObject + testSlice2 []*ReportObject + expectedResult bool + }{ + { + testSlice1: []*ReportObject{{ObjectType: "test1"}}, + testSlice2: []*ReportObject{{ObjectType: "test1"}}, + expectedResult: true, + }, + { + testSlice1: []*ReportObject{{ObjectType: "test1"}}, + testSlice2: []*ReportObject{{ObjectType: "test2"}}, + expectedResult: false, + }, + { + testSlice1: []*ReportObject{{ObjectType: "test1"}}, + testSlice2: []*ReportObject{{ObjectType: "test1"}, {ObjectType: "test2"}}, + expectedResult: false, + }, + { + testSlice1: []*ReportObject{{ObjectType: "test1"}, {ObjectType: "test2"}}, + testSlice2: nil, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + assert.Equal(t, testCase.expectedResult, Equal(testCase.testSlice1, testCase.testSlice2)) + } +} + +func TestGetNoServicesUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Services: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Services: []*corev1.Service{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoServicesUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetDaemonSetFailedToSpawnSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{DaemonsetFailedToSpawn: true}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{DaemonsetFailedToSpawn: false}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetDaemonSetFailedToSpawnSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetSharedProcessNamespacePodsSkipFn(t *testing.T) { + newProviderPod := func(shareProcessNamespace *bool) *provider.Pod { + return &provider.Pod{ + Pod: &corev1.Pod{ + Spec: corev1.PodSpec{ + ShareProcessNamespace: shareProcessNamespace, + }, + }, + } + } + + trueVar := true + falseVar := false + + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + newProviderPod(nil), + }}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + newProviderPod(&trueVar), + }}, + expectedResult: false, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + newProviderPod(&falseVar), + }}, + expectedResult: true, + }, + } + + for _, testCase := range testCases { + results, _ := GetSharedProcessNamespacePodsSkipFn(testCase.testEnv)() + assert.Equal(t, testCase.expectedResult, results) + } +} + +func TestGetNoContainersUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Containers: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Containers: []*provider.Container{ + { + Container: &corev1.Container{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoContainersUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoPodsUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Pods: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + { + Pod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoPodsUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoDeploymentsUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Deployments: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Deployments: []*provider.Deployment{ + { + Deployment: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoDeploymentsUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoStatefulSetsUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{StatefulSets: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{StatefulSets: []*provider.StatefulSet{ + { + StatefulSet: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoStatefulSetsUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoCrdsUnderTestSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Crds: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Crds: []*apiextv1.CustomResourceDefinition{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoCrdsUnderTestSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoNamespacesSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Namespaces: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Namespaces: []string{"test1"}}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoNamespacesSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoRolesSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Roles: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Roles: []rbacv1.Role{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoRolesSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoPersistentVolumesSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{PersistentVolumes: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{PersistentVolumes: []corev1.PersistentVolume{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoPersistentVolumesSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNotEnoughWorkersSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Nodes: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{ + Nodes: map[string]provider.Node{ + "test1": { + Data: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Labels: map[string]string{ + "node-role.kubernetes.io/worker": "", + }, + }, + }, + }, + }, + }, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNotEnoughWorkersSkipFn(testCase.testEnv, 1) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetPodsWithoutAffinityRequiredLabelSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Pods: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + { + Pod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Labels: map[string]string{ + "AffinityRequired": "true", + }, + }, + }, + }, + }}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + { + Pod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Labels: map[string]string{ + "UnrelatedLabel": "true", + }, + }, + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetPodsWithoutAffinityRequiredLabelSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoAffinityRequiredPodsSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{Pods: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + { + Pod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Labels: map[string]string{ + "AffinityRequired": "true", + }, + }, + }, + }, + }}, + expectedResult: false, + }, + { + testEnv: &provider.TestEnvironment{Pods: []*provider.Pod{ + { + Pod: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Labels: map[string]string{ + "AffinityRequired": "false", + }, + }, + }, + }, + }}, + expectedResult: true, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoAffinityRequiredPodsSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoStorageClassesSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{StorageClassList: nil}, + expectedResult: true, + }, + { + testEnv: &provider.TestEnvironment{StorageClassList: []storagev1.StorageClass{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }, + }, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoStorageClassesSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoPersistentVolumeClaimsSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + {testEnv: &provider.TestEnvironment{PersistentVolumeClaims: nil}, expectedResult: true}, + { + testEnv: &provider.TestEnvironment{PersistentVolumeClaims: []corev1.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + }}, + expectedResult: false, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoPersistentVolumeClaimsSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoBareMetalNodesSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + { + testEnv: &provider.TestEnvironment{ + Nodes: map[string]provider.Node{ + "test1": { + Data: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + Spec: corev1.NodeSpec{ + ProviderID: "baremetalhost://test1", + }, + }, + }, + }, + }, expectedResult: false, + }, + { + testEnv: &provider.TestEnvironment{ + Nodes: map[string]provider.Node{ + "test1": { + Data: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + Spec: corev1.NodeSpec{ + ProviderID: "test1", + }, + }, + }, + }, + }, expectedResult: true, + }, + } + + for _, testCase := range testCases { + testFunc := GetNoBareMetalNodesSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoIstioSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + {testEnv: &provider.TestEnvironment{IstioServiceMeshFound: false}, expectedResult: true}, + {testEnv: &provider.TestEnvironment{IstioServiceMeshFound: true}, expectedResult: false}, + } + + for _, testCase := range testCases { + testFunc := GetNoIstioSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +} + +func TestGetNoOperatorsSkipFn(t *testing.T) { + testCases := []struct { + testEnv *provider.TestEnvironment + expectedResult bool + }{ + {testEnv: &provider.TestEnvironment{Operators: nil}, expectedResult: true}, + {testEnv: &provider.TestEnvironment{Operators: []*provider.Operator{ + { + Name: "test1", + }, + }}, expectedResult: false}, + } + + for _, testCase := range testCases { + testFunc := GetNoOperatorsSkipFn(testCase.testEnv) + result, _ := testFunc() + assert.Equal(t, testCase.expectedResult, result) + } +}