package mapper import ( "encoding/json" "fmt" "slices" "testing" virtv1 "kubevirt.io/api/core/v1" "edge-infra.dev/pkg/edge/api/graph/model" "edge-infra.dev/pkg/edge/api/status" "edge-infra.dev/pkg/edge/api/types" "edge-infra.dev/pkg/edge/api/utils" persistence "edge-infra.dev/pkg/edge/apis/persistence/v1alpha1" helmAPIv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1" "github.com/fluxcd/pkg/apis/kustomize" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" ) const ( chartVersion = "1.0.0" helmSecret = "helm-repo-secret" persistencePatch = "- op: replace\n path: /spec/nodeSelectorTerms\n value:" ) // Test ToHelmRepositoriesModels func TestToHelmRepositoriesModel(t *testing.T) { helmRepo1 := GetTestHelmRepositorySecret() helmRepo2 := GetTestHelmRepositorySecret() repos := []*model.SecretManagerResponse{helmRepo1, helmRepo2} releaseModels := ToHelmRepositoriesModels(repos) for i, releaseModel := range releaseModels { VerifyHelmRepositoryEqualModel(repos[i], releaseModel, t) } } // Test ToHelmReleasesModels func TestToHelmReleasesModels(t *testing.T) { helmRelease1 := getTestHelmRelease() helmRelease2 := getTestHelmRelease() releases := []helmAPIv2beta1.HelmRelease{*helmRelease1, *helmRelease2} helmReleaseData := getTestHelmReleaseData(releases) releaseModels := ToHelmReleasesModels(releases, helmReleaseData) for i, releaseModel := range releaseModels { conditions := releases[i].Status.Conditions conditionTime := conditions[len(conditions)-1].LastTransitionTime.Format(TimeFormat) releaseModelJSON, _ := utils.YAMLToJSON(releaseModel.ConfigValues) assert.Equal(t, releases[i].Name, releaseModel.Name) assert.Equal(t, releases[i].Spec.Chart.Spec.Chart, releaseModel.HelmChart) assert.Equal(t, conditionTime, releaseModel.LastActionTime) assert.Equal(t, releaseModel.StatusType, "Failed") assert.Equal(t, releaseModel.VersionInstalled, "") //"2.0.1" assert.Equal(t, releaseModel.VersionRequested, "2.0.x") assert.Equal(t, releases[i].Spec.TargetNamespace, releaseModel.Namespace) assert.JSONEq(t, string(releases[i].Spec.Values.Raw), string(releaseModelJSON)) } } // Test ToHelmReleasesStatusModels func TestToHelmReleasesStatusModels(t *testing.T) { helmRelease1 := getTestHelmRelease() helmRelease2 := getTestHelmRelease() releases := []helmAPIv2beta1.HelmRelease{*helmRelease1, *helmRelease2} releaseModels := ToHelmReleasesStatusModels(releases) for i, releaseModel := range releaseModels { conditions := releases[i].Status.Conditions conditionTime := conditions[len(conditions)-1].LastTransitionTime.Format(TimeFormat) releaseModelJSON, _ := utils.YAMLToJSON(releaseModel.ConfigValues) assert.Equal(t, releases[i].Name, releaseModel.Name) assert.Equal(t, conditionTime, releaseModel.LastActionTime) assert.Equal(t, releaseModel.StatusType, "Failed") assert.Equal(t, releaseModel.VersionInstalled, "") //2.0.1 assert.Equal(t, releaseModel.VersionRequested, "2.0.x") assert.JSONEq(t, string(releases[i].Spec.Values.Raw), string(releaseModelJSON)) } } // Test ToHelmStatus: testing if true func TestToHelmStatusTrue(t *testing.T) { result := ToHelmStatus("True") assert.Equal(t, result, "Succeeded") } // Test ToHelmStatus: testing if false func TestToHelmStatusFail(t *testing.T) { result := ToHelmStatus("False") assert.Equal(t, result, "Failed") } // Test ToPodStatus: testing if true func TestToPodStatusTrue(t *testing.T) { result := ToPodStatus("True") assert.Equal(t, result, status.Running) } // Test ToPodStatus: testing if false func TestToPodStatusFalse(t *testing.T) { result := ToPodStatus("False") assert.Equal(t, result, status.Error) } // Test ToCreateHelmRelease func TestToCreateHelmReleaseNil(t *testing.T) { helm := getCreateHelmReleaseCreate(HelmReleaseNamespace, "") model, err := ToCreateHelmRelease(name, helmRepository, helmChart, version, "", "", nil, model.WorkloadInstallationTypeServerPreferred, nil, "0.20", "") assert.NoError(t, err) assert.Equal(t, model.GetLabels()["parent-cluster"], Region) verifyHelmReleaseEqualModel(helm, model.(*helmAPIv2beta1.HelmRelease), t) } // Test ToCreateHelmRelease: with namespace field func TestToCreateHelmReleaseNamespace(t *testing.T) { namespace := "flux-system" helm := getCreateHelmReleaseCreate(HelmReleaseNamespace, namespace) model, err := ToCreateHelmRelease(name, helmRepository, helmChart, version, "", namespace, nil, model.WorkloadInstallationTypeServerPreferred, nil, "0.20", "") assert.NoError(t, err) assert.Equal(t, model.GetLabels()["parent-cluster"], Region) verifyHelmReleaseEqualModel(helm, model.(*helmAPIv2beta1.HelmRelease), t) } // Test ToCreateHelmRelease: with namespace and configMap field func TestToCreateHelmReleaseNamespaceConvertConfigMap(t *testing.T) { configMap := []byte(`{"replicaCount" : 2}`) model, err := ToCreateHelmRelease(name, helmRepository, helmChart, version, "", namespace, configMap, model.WorkloadInstallationTypeServerPreferred, nil, "0.20", "") assert.NoError(t, err) assert.Equal(t, model.(*helmAPIv2beta1.HelmRelease).Spec.Values.Raw, configMap) } // Test ToHelmChartResponse func TestToHelmChartResponse(t *testing.T) { var versions []*string name := "alert-manager" mockVersions := []string{"0.3.0", "0.2.0", "0.1.4", "0.1.3", "0.1.2", "0.1.1"} for i := range mockVersions { versions = append(versions, &mockVersions[i]) //nolint } helmChartVersions := getHelmChartVersions(name, versions) model := ToHelmChartResponse(name, versions) verifyHelmChartResponseModel(helmChartVersions, model, t) } func ToConvertTestUnstructuredToHelmReleases(resources *unstructured.UnstructuredList) ([]helmAPIv2beta1.HelmRelease, error) { resp := make([]helmAPIv2beta1.HelmRelease, 0) for _, item := range resources.Items { converted := &helmAPIv2beta1.HelmRelease{} err := runtime.DefaultUnstructuredConverter. FromUnstructured(item.UnstructuredContent(), &converted) if err != nil { return nil, err } resp = append(resp, *converted) } return resp, nil } func TestConvertToConfigMapData(t *testing.T) { res := []string{"{\"apiVersion\":\"v1\",\"data\":{\"banner.id\":\"3396a52c-6a22-4049-9593-5a63b596a100\",\"bsl.organization\":\"test-org\",\"cluster.edge.id\":\"3396a52c-6a22-4049-9593-5a63b596a201\",\"cluster.fleet\":\"fleet\",\"cluster.location\":\"region-infra\",\"cluster.name\":\"test-store\",\"cluster.type\":\"store\",\"edge.banner\":\"test-org\",\"edge.project.id\":\"test-org\",\"foreman.project.id\":\"topLevelProjectId\"},\"kind\":\"ConfigMap\",\"metadata\":{\"creationTimestamp\":null,\"name\":\"edge-info\",\"namespace\":\"kube-public\",\"resourceVersion\":\"1\"}}"} configMaps, err := ConvertToConfigMapData(res) assert.NoError(t, err) assert.NotEmpty(t, configMaps) assert.Equal(t, 10, len(configMaps)) } func TestUpdateHelmWorkload(t *testing.T) { helmWorkload := &model.HelmWorkload{ HelmEdgeID: "123456", Name: "testHelmWorkload", HelmChart: "test", CreatedAt: "2022-10-19 17:34:04.174736+00", UpdatedAt: "2022-10-19 17:34:04.174736+00", HelmChartVersion: "2.8.0", ConfigValues: nil, Namespace: "testNamespace", HelmRepoSecret: "testHelmRepoSecret", InstalledBy: nil, UpdateAvailable: nil, UpgradeableVersions: nil, DowngradeableVersions: nil, Secrets: nil, } helmConfig := "{testHelmConfigString}" helmWorkload.ConfigValues = &helmConfig installedBy := "" helmWorkload.InstalledBy = &installedBy var versions []*string mockVersions := []string{"3.0.0", "2.8.0", "0.1.4", "0.1.3"} for i := range mockVersions { versions = append(versions, &mockVersions[i]) } var secrets []*model.HelmSecrets mockSecrets := []model.HelmSecrets{ { SecretEdgeID: "bbf70912-2c0a-4df1-a588-a1d16303be31", Name: "test-secret1", CreatedAt: "2022-10-19T13:34:56.458324-04:00", UpdatedAt: "2022-10-19T13:34:56.458324-04:00", }, { SecretEdgeID: "bbf70912-2c0a-4df1-a588-a1d16303be31", Name: "test-secret2", CreatedAt: "2022-10-19T13:34:56.458324-04:00", UpdatedAt: "2022-10-19T13:34:56.458324-04:00", }, } for i := range mockSecrets { secrets = append(secrets, &mockSecrets[i]) } resultHelmWorkload := UpdateHelmWorkload(helmWorkload, versions, secrets, nil, nil) assert.Equal(t, resultHelmWorkload.Name, "testHelmWorkload") assert.Equal(t, len(resultHelmWorkload.Secrets), 2) assert.Equal(t, len(resultHelmWorkload.UpgradeableVersions), 1) assert.Equal(t, len(resultHelmWorkload.DowngradeableVersions), 2) } // Test Post Renderer Specs for Helm Release Object func TestToCreateHelmReleasePostRendererPatchStrings(t *testing.T) { type test struct { testName string installationType model.WorkloadInstallationType expectedLen int expectedPatchStr string operator string } tests := []test{ { testName: "installationTypeServerPreferred", expectedLen: 6, operator: "\"operator\":\"In\"", installationType: model.WorkloadInstallationTypeServerPreferred, expectedPatchStr: "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"preferredDuringSchedulingIgnoredDuringExecution\":[{\"weight\":1,\"preference\":{\"matchExpressions\":[{\"key\":\"node.ncr.com/class\",\"operator\":\"In\",\"values\":[\"server\"]}]}}]} }", }, { testName: "installationTypeAny", expectedLen: 6, operator: "\"operator\":\"In\"", installationType: model.WorkloadInstallationTypeAny, expectedPatchStr: "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"preferredDuringSchedulingIgnoredDuringExecution\":[{\"weight\":1,\"preference\":{\"matchExpressions\":[{\"key\":\"node.ncr.com/class\",\"operator\":\"In\",\"values\":[\"server\"]}]}}]} }", }, { testName: "installationTypeTouchPoint", expectedLen: 8, operator: "\"operator\":\"NotIn\"", installationType: model.WorkloadInstallationTypeTouchpoint, expectedPatchStr: "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"node.ncr.com/class\",\"operator\":\"NotIn\",\"values\":[\"server\"]}]}]}} }", }, { testName: "installationTypeServer", expectedLen: 8, operator: "\"operator\":\"In\"", installationType: model.WorkloadInstallationTypeServer, expectedPatchStr: "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"node.ncr.com/class\",\"operator\":\"In\",\"values\":[\"server\"]}]}]}} }", }, { testName: "installationTypeNoMod", expectedLen: 1, operator: "", installationType: model.WorkloadInstallationTypeNoMod, expectedPatchStr: "", }, { testName: "installationTypeAdvanced", expectedLen: 1, operator: "", installationType: model.WorkloadInstallationTypeNoMod, expectedPatchStr: "", }, } for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { helmRelease, err := ToCreateHelmRelease(name, helmRepository, helmChart, chartVersion, helmSecret, namespace, nil, tc.installationType, nil, "0.20", "") assert.NoError(t, err) assert.NotNil(t, helmRelease) if tc.testName == "installationTypeServer" || tc.testName == "installationTypeTouchPoint" { patchPersStrFromSpec := helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches[len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches)-1].Patch assert.Contains(t, patchPersStrFromSpec, persistencePatch) } if tc.testName == "installationTypeNoMod" || tc.testName == "installationTypeAdvanced" { assert.Equal(t, tc.expectedLen, len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers)) assert.Equal(t, []helmAPIv2beta1.PostRenderer{ { Kustomize: &helmAPIv2beta1.Kustomize{ Patches: make([]kustomize.Patch, 0), }, }, }, helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers) } else { patchStrFromSpec := helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches[0].Patch assert.Equal(t, tc.expectedLen, len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches)) assert.Contains(t, patchStrFromSpec, tc.operator) assert.Equal(t, tc.expectedPatchStr, patchStrFromSpec) } }) } } func TestToCreateHelmReleasePostRendererPatchStringsTypeAdvanced(t *testing.T) { type test struct { testName string installationType model.WorkloadInstallationType expectedLen int expectedPatchStr string operator string } customLabels := []*model.Label{ {Key: "custom-1", Description: "label 1"}, {Key: "custom-2", Description: "label 2"}, } tests := []test{ { testName: "installationTypeAdvanced", expectedLen: 8, operator: "Exists", installationType: model.WorkloadInstallationTypeAdvanced, expectedPatchStr: "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/custom-1\",\"operator\":\"Exists\"},{\"key\":\"custom.node.ncr.com/custom-2\",\"operator\":\"Exists\"}]}]}} }", }, } for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { helmRelease, err := ToCreateHelmRelease(name, helmRepository, helmChart, chartVersion, helmSecret, namespace, nil, tc.installationType, customLabels, "0.20", "") assert.NoError(t, err) assert.NotNil(t, helmRelease) patchStrFromSpec := helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches[0].Patch assert.Equal(t, tc.expectedLen, len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches)) assert.Contains(t, patchStrFromSpec, tc.operator) assert.Equal(t, tc.expectedPatchStr, patchStrFromSpec) patchPersStrFromSpec := helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches[len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches)-1].Patch assert.Contains(t, patchPersStrFromSpec, persistencePatch) }) } } func TestToCreateHelmReleasePostRendererPatchTargets(t *testing.T) { type test struct { testName string installationType model.WorkloadInstallationType expectedLen int expectedVersion string patchTargets []string } tests := []test{ { testName: "installationTypeServerPreferred", expectedLen: 6, installationType: model.WorkloadInstallationTypeServerPreferred, expectedVersion: "v1", patchTargets: []string{"Deployment", "StatefulSet", "ReplicaSet", "Job", "CronJob", "VirtualMachine"}, }, { testName: "installationTypeAdvanced", expectedLen: 1, installationType: model.WorkloadInstallationTypeAdvanced, expectedVersion: "v1", patchTargets: []string{}, }, { testName: "installationTypeAny", expectedLen: 6, installationType: model.WorkloadInstallationTypeAny, expectedVersion: "v1", patchTargets: []string{"Deployment", "StatefulSet", "ReplicaSet", "Job", "CronJob", "VirtualMachine"}, }, { testName: "installationTypeTouchPoint", expectedLen: 8, installationType: model.WorkloadInstallationTypeTouchpoint, expectedVersion: "v1", patchTargets: []string{"Deployment", "StatefulSet", "DaemonSet", "ReplicaSet", "Job", "CronJob", "VirtualMachine", persistence.Kind}, }, { testName: "installationTypeServer", expectedLen: 8, installationType: model.WorkloadInstallationTypeServer, expectedVersion: "v1", patchTargets: []string{"Deployment", "StatefulSet", "DaemonSet", "ReplicaSet", "Job", "CronJob", "VirtualMachine", persistence.Kind}, }, { testName: "installationTypeNoMod", expectedLen: 1, installationType: model.WorkloadInstallationTypeNoMod, expectedVersion: "", patchTargets: []string{}, }, } for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { helmRelease, err := ToCreateHelmRelease(name, helmRepository, helmChart, chartVersion, helmSecret, namespace, nil, tc.installationType, nil, "0.20", "") assert.NoError(t, err) assert.NotNil(t, helmRelease) if tc.testName == "installationTypeNoMod" || tc.testName == "installationTypeAdvanced" { //nolint:nestif assert.Equal(t, tc.expectedLen, len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers)) assert.Equal(t, []helmAPIv2beta1.PostRenderer{ { Kustomize: &helmAPIv2beta1.Kustomize{ Patches: make([]kustomize.Patch, 0), }, }, }, helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers) } else { totalPatchesLen := len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches) // patch target length should match list of expected Patch Targets assert.Equal(t, tc.expectedLen, totalPatchesLen) assert.Equal(t, len(tc.patchTargets), totalPatchesLen) for _, patch := range helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches { if patch.Target.Kind == persistence.Kind { assert.Equal(t, persistence.GroupVersion.Version, patch.Target.Version) assert.Contains(t, patch.Patch, "- op: replace\n path: /spec/nodeSelectorTerms\n value: ") } else if patch.Target.Kind == "CronJob" { assert.Equal(t, tc.expectedVersion, patch.Target.Version) assert.Contains(t, patch.Patch, "- op: add\n path: /spec/jobTemplate/spec/template/spec/affinity\n value: {\"nodeAffinity\": ") } else if patch.Target.Kind == "VirtualMachine" { assert.Equal(t, tc.expectedVersion, patch.Target.Version) assert.Equal(t, "kubevirt.io", patch.Target.Group) assert.Contains(t, patch.Patch, "- op: add\n path: /spec/template/spec/affinity\n value:\n nodeAffinity:") assert.Contains(t, patch.Patch, "- op: add\n path: /spec/template/metadata/annotations/edge.ncr.com~1helm-edge-id\n value: \"\"\n") } else { assert.Equal(t, tc.expectedVersion, patch.Target.Version) assert.Contains(t, patch.Patch, "- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": ") } assert.Contains(t, tc.patchTargets, patch.Target.Kind) } } }) } } func TestToCreateHelmReleasePostRendererPatchTargetsAdvanced(t *testing.T) { type test struct { testName string installationType model.WorkloadInstallationType expectedLen int expectedVersion string patchTargets []string } customLabels := []*model.Label{ {Key: "custom-1", Description: "label 1"}, {Key: "custom-2", Description: "label 2"}, } tests := []test{ { testName: "installationTypeAdvanced", expectedLen: 8, installationType: model.WorkloadInstallationTypeAdvanced, expectedVersion: "v1", patchTargets: []string{"Deployment", "DaemonSet", "StatefulSet", "ReplicaSet", "Job", "CronJob", "VirtualMachine", persistence.Kind}, }, } for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { helmRelease, err := ToCreateHelmRelease(name, helmRepository, helmChart, chartVersion, helmSecret, namespace, nil, tc.installationType, customLabels, "0.20", "") assert.NoError(t, err) assert.NotNil(t, helmRelease) totalPatchesLen := len(helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches) // patch target length should match list of expected Patch Targets assert.Equal(t, tc.expectedLen, totalPatchesLen) assert.Equal(t, len(tc.patchTargets), totalPatchesLen) for _, patch := range helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches { if patch.Target.Kind == persistence.Kind { assert.Equal(t, persistence.GroupVersion.Version, patch.Target.Version) } else { assert.Equal(t, tc.expectedVersion, patch.Target.Version) } assert.Contains(t, tc.patchTargets, patch.Target.Kind) } }) } } func TestToHelmVersion(t *testing.T) { type test struct { testName string helmWorkloadQueryData types.HelmWorkloadQuery helmWorkload *model.HelmWorkload expectedLen int } helmConfig := "testHelmConfig" installedBy := "testInstalledBy" helmWorkloadQueryData := types.HelmWorkloadQuery{ ClusterEdgeID: "testClusterEdgeID", HelmEdgeID: "be8536ff-d463-4aff-8fa9-fe81fec1ddc1", Name: "test-helm-workload", Namespace: "nginx", HelmChart: "nginx", HelmRepository: "test-repo", HelmChartVersion: "2.3.1", HelmConfig: &helmConfig, InstalledBy: &installedBy, WorkloadInstallationType: "mockInstallationType", CreatedAt: "mockCreatedAt", UpdatedAt: "mockUpdatedAt", HelmRepoSecret: "test-helm-workload", ProjectID: "mockProjectID", } helmWorkload := &model.HelmWorkload{ HelmEdgeID: helmWorkloadQueryData.HelmEdgeID, HelmChart: helmWorkloadQueryData.HelmChart, Name: helmWorkloadQueryData.Name, HelmRepository: helmWorkloadQueryData.HelmRepository, CreatedAt: helmWorkloadQueryData.CreatedAt, UpdatedAt: helmWorkloadQueryData.UpdatedAt, HelmChartVersion: helmWorkloadQueryData.HelmChartVersion, ConfigValues: helmWorkloadQueryData.HelmConfig, Namespace: helmWorkloadQueryData.Namespace, HelmRepoSecret: helmWorkloadQueryData.HelmRepoSecret, InstalledBy: helmWorkloadQueryData.InstalledBy, InstallationType: &helmWorkloadQueryData.WorkloadInstallationType, ClusterEdgeID: helmWorkloadQueryData.ClusterEdgeID, } tests := []test{ { testName: "happyPath", expectedLen: 3, helmWorkloadQueryData: helmWorkloadQueryData, helmWorkload: helmWorkload, }, } for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { helmWorkload := ToHelmWorkload(tc.helmWorkloadQueryData) assert.Equal(t, tc.helmWorkload, helmWorkload) }) } } func TestToCreateHelmRelease(t *testing.T) { helmEdgeID := "3cf1e89e-8338-4227-b93c-3d56a8075f83" testcases := []struct { title string name string helmRepository string helmChart string version string secretManagerSecret string namespace string configMap []byte installationType model.WorkloadInstallationType customLabels []*model.Label storeversion string expected string }{ { title: "Test Case 1 - No Mod - 0.21", name: "testOne", helmRepository: "edge-test", helmChart: "podinfo", version: "1.0", secretManagerSecret: "edge-helm", namespace: "default", configMap: nil, installationType: model.WorkloadInstallationTypeNoMod, customLabels: nil, storeversion: "0.21", expected: `{"kind":"HelmRelease","apiVersion":"helm.toolkit.fluxcd.io/v2","metadata":{"name":"testOne","namespace":"flux-system","creationTimestamp":null,"labels":{"parent-cluster":"region-infra","secret-mamager.edge.ncr.com":"edge-helm"}},"spec":{"chart":{"spec":{"chart":"podinfo","version":"1.0","sourceRef":{"kind":"HelmRepository","name":"edge-test"}}},"interval":"2m0s","releaseName":"testOne","targetNamespace":"default","timeout":"15m0s","driftDetection":{"mode":"enabled"},"install":{"remediation":{"retries":3}},"upgrade":{"remediation":{"retries":3}},"postRenderers":[{"kustomize":{"patches":[{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"IENPatch"}},{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"StatefulSet"}},{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"DaemonSet"}}]}}]},"status":{}}`, }, { title: "Test Case 2 - No Mod - 0.19 (No Patches)", name: "testTwo", helmRepository: "edge-test", helmChart: "podinfo", version: "1.0", secretManagerSecret: "edge-helm", namespace: "default", configMap: nil, installationType: model.WorkloadInstallationTypeNoMod, customLabels: nil, storeversion: "0.19", expected: `{"kind":"HelmRelease","apiVersion":"helm.toolkit.fluxcd.io/v2beta1","metadata":{"name":"testTwo","namespace":"flux-system","creationTimestamp":null,"labels":{"parent-cluster":"region-infra","secret-mamager.edge.ncr.com":"edge-helm"}},"spec":{"chart":{"spec":{"chart":"podinfo","version":"1.0","sourceRef":{"kind":"HelmRepository","name":"edge-test"}}},"interval":"2m0s","releaseName":"testTwo","targetNamespace":"default","timeout":"15m0s","install":{"remediation":{"retries":3}},"upgrade":{"remediation":{"retries":3}},"postRenderers":[{"kustomize":{}}]},"status":{}}`, }, { title: "Test Case 3 - Advanced Install Type - 0.21 (Node Targeting & Drift Detection Patches)", name: "testThree", helmRepository: "edge-test", helmChart: "podinfo", version: "1.0", secretManagerSecret: "edge-helm", namespace: "default", configMap: nil, installationType: model.WorkloadInstallationTypeAdvanced, customLabels: []*model.Label{ { Key: "hello", Description: "world", }, }, storeversion: "0.21", expected: `{"kind":"HelmRelease","apiVersion":"helm.toolkit.fluxcd.io/v2","metadata":{"name":"testThree","namespace":"flux-system","creationTimestamp":null,"labels":{"parent-cluster":"region-infra","secret-mamager.edge.ncr.com":"edge-helm"}},"spec":{"chart":{"spec":{"chart":"podinfo","version":"1.0","sourceRef":{"kind":"HelmRepository","name":"edge-test"}}},"interval":"2m0s","releaseName":"testThree","targetNamespace":"default","timeout":"15m0s","driftDetection":{"mode":"enabled"},"install":{"remediation":{"retries":3}},"upgrade":{"remediation":{"retries":3}},"postRenderers":[{"kustomize":{"patches":[{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"IENPatch"}},{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"StatefulSet"}},{"patch":"- op: add\n path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection\n value: disabled","target":{"version":"v1","kind":"DaemonSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"Deployment"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"StatefulSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"DaemonSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"ReplicaSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"Job"}},{"patch":"- op: add\n path: /spec/jobTemplate/spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"CronJob"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: custom.node.ncr.com/hello\n operator: Exists\n- op: add\n path: /spec/template/metadata/annotations/edge.ncr.com~1helm-edge-id\n value: 3cf1e89e-8338-4227-b93c-3d56a8075f83\n","target":{"group":"kubevirt.io","version":"v1","kind":"VirtualMachine"}},{"patch":"- op: replace\n path: /spec/nodeSelectorTerms\n value: [{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]","target":{"group":"edge.ncr.com","version":"v1alpha1","kind":"Persistence"}}]}}]},"status":{}}`, }, { title: "Test Case 4 - Advanced Install Type - 0.19 (Node Targeting Patch)", name: "testFour", helmRepository: "edge-test", helmChart: "podinfo", version: "1.0", secretManagerSecret: "edge-helm", namespace: "default", configMap: nil, installationType: model.WorkloadInstallationTypeAdvanced, customLabels: []*model.Label{ { Key: "hello", Description: "world", }, }, storeversion: "0.19", expected: `{"kind":"HelmRelease","apiVersion":"helm.toolkit.fluxcd.io/v2beta1","metadata":{"name":"testFour","namespace":"flux-system","creationTimestamp":null,"labels":{"parent-cluster":"region-infra","secret-mamager.edge.ncr.com":"edge-helm"}},"spec":{"chart":{"spec":{"chart":"podinfo","version":"1.0","sourceRef":{"kind":"HelmRepository","name":"edge-test"}}},"interval":"2m0s","releaseName":"testFour","targetNamespace":"default","timeout":"15m0s","install":{"remediation":{"retries":3}},"upgrade":{"remediation":{"retries":3}},"postRenderers":[{"kustomize":{"patches":[{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"Deployment"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"StatefulSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"DaemonSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"ReplicaSet"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"Job"}},{"patch":"- op: add\n path: /spec/jobTemplate/spec/template/spec/affinity\n value: {\"nodeAffinity\": {\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]}} }","target":{"version":"v1","kind":"CronJob"}},{"patch":"- op: add\n path: /spec/template/spec/affinity\n value:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: custom.node.ncr.com/hello\n operator: Exists\n- op: add\n path: /spec/template/metadata/annotations/edge.ncr.com~1helm-edge-id\n value: 3cf1e89e-8338-4227-b93c-3d56a8075f83\n","target":{"group":"kubevirt.io","version":"v1","kind":"VirtualMachine"}},{"patch":"- op: replace\n path: /spec/nodeSelectorTerms\n value: [{\"matchExpressions\":[{\"key\":\"custom.node.ncr.com/hello\",\"operator\":\"Exists\"}]}]","target":{"group":"edge.ncr.com","version":"v1alpha1","kind":"Persistence"}}]}}]},"status":{}}`, }, } for _, testcase := range testcases { t.Run(testcase.title, func(t *testing.T) { hr, err := ToCreateHelmRelease(testcase.name, testcase.helmRepository, testcase.helmChart, testcase.version, testcase.secretManagerSecret, testcase.namespace, testcase.configMap, testcase.installationType, testcase.customLabels, testcase.storeversion, helmEdgeID) assert.NoError(t, err) res, err := json.Marshal(hr) assert.NoError(t, err) assert.Equal(t, testcase.expected, string(res)) }) } } func TestVirtualMachinePatches(t *testing.T) { helmEdgeID := "c014b82f-c5c8-4186-8bba-1ca89fb28793" helmRelease, err := ToCreateHelmRelease(name, helmRepository, helmChart, chartVersion, helmSecret, namespace, nil, model.WorkloadInstallationTypeServer, nil, "0.20", helmEdgeID) assert.NoError(t, err) assert.NotNil(t, helmRelease) patchList := helmRelease.(*helmAPIv2beta1.HelmRelease).Spec.PostRenderers[0].Kustomize.Patches expectedTarget := kustomize.Selector{ Kind: "VirtualMachine", Group: virtv1.GroupVersion.Group, Version: virtv1.GroupVersion.Version, } expectedPatch := fmt.Sprintf(`- op: add path: /spec/template/spec/affinity value: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node.ncr.com/class operator: In values: - server - op: add path: /spec/template/metadata/annotations/edge.ncr.com~1helm-edge-id value: %s `, helmEdgeID) assert.True(t, slices.ContainsFunc(patchList, func(patch kustomize.Patch) bool { return patch.Target != nil && *patch.Target == expectedTarget && patch.Patch == expectedPatch })) }