package services import ( "context" _ "embed" "encoding/base64" "encoding/json" "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" pubSub "cloud.google.com/go/pubsub" "github.com/DATA-DOG/go-sqlmock" helmApi "github.com/fluxcd/helm-controller/api/v2" "github.com/fluxcd/pkg/apis/meta" helmRepositoryApi "github.com/fluxcd/source-controller/api/v1" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/thoas/go-funk" "google.golang.org/api/option" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/repo" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/yaml" sqlerr "edge-infra.dev/pkg/edge/api/apierror/sql" "edge-infra.dev/pkg/edge/api/bsl/types" "edge-infra.dev/pkg/edge/api/graph/mapper" "edge-infra.dev/pkg/edge/api/graph/model" "edge-infra.dev/pkg/edge/api/middleware" "edge-infra.dev/pkg/edge/api/mocks" sqlquery "edge-infra.dev/pkg/edge/api/sql" "edge-infra.dev/pkg/edge/api/status" edgetypes "edge-infra.dev/pkg/edge/api/types" helmTypes "edge-infra.dev/pkg/edge/api/types" chariotAPI "edge-infra.dev/pkg/edge/chariot/client" "edge-infra.dev/pkg/edge/constants" "edge-infra.dev/pkg/edge/externalsecrets" chariotClientApiTestutils "edge-infra.dev/test/framework/gcp/pubsub" ) const ( apiVersion = "clusterregistry.k8s.io/v1alpha1" bannerEdgeID = "banner_edge_id" clusterEdgeID = "cluster_edge_id" clusterExternalSecret = "ClusterExternalSecret" chartName = "helm_chart" chartVersion = "1.0.0" testTime = "2022-01-01 12:00:00" helmSecret = "helm_secret" helmRepoKind = "HelmRepository" helmRepoURL = "https://example.com" readme = `# Helm Application` testChariotPubsubTopic = "chariot-pubsub-topic" testChariotPubsubSubscription = "chariot-pubsub-subscription" testHelmRepo = "helm_repo" helmRelease = "HelmRelease" namespace = "Namespace" externalSecret = "ExternalSecret" configSchema = ` { "$id": "https://example.com/geographical-location.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Longitude and Latitude Values", "description": "geographical coordinates.", "required": [ "latitude", "longitude" ], "type": "object", "properties": { "latitude": { "type": "number", "minimum": -90, "maximum": 90 }, "longitude": { "type": "number", "minimum": -180,r "maximum": 180 } } } ` configValue = ` { "latitude": 50, "longitude": 30 } ` helmEdgeID = "be8536ff-d463-4aff-8fa9-fe81fec1ddc1" testClusterEdgeID = "3396a52c-6a22-4049-9593-5a63b596a200" testBannerEdgeID = "3396a52c-6a22-4049-9593-5a63b596a201" ) var ns = "default" var appConfig = &edgetypes.Config{Chariot: edgetypes.ChariotConfig{}} var jsonConfig = "{\"version\":10}" //go:embed testdata/alpine-0.2.0.tgz var zippedChart string func TestHelmService_CreateAndDeleteBannerHelmRepo(t *testing.T) { name := "test-repo" db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.MatchExpectationsInOrder(true) helmWorkload := getTestHelmWorkloadQuery() mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID). WithArgs(bannerEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( helmWorkload.ClusterEdgeID, helmWorkload.BannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID). WithArgs(bannerEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( helmWorkload.ClusterEdgeID, helmWorkload.BannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, "", helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) assertSubscriptionMessage := func(message *pubSub.Message) { msg := &chariotAPI.ChariotMessage{} err := json.Unmarshal(message.Data, msg) if err != nil { fmt.Println(err) } assert.Equal(t, projectID, msg.Banner) if len(msg.Objects) > 0 { for _, obj := range msg.Objects { decoded, err := base64.StdEncoding.DecodeString(obj) assert.NoError(t, err) res := strings.Split(string(decoded), ",") objKind := res[0][9 : len(res[0])-1] switch objKind { case clusterExternalSecret: helmRepoMsg := &helmRepositoryApi.HelmRepository{} err = json.Unmarshal(decoded, &helmRepoMsg) assert.NoError(t, err) assert.Equal(t, clusterExternalSecret, helmRepoMsg.Kind) assert.Equal(t, name, helmRepoMsg.ObjectMeta.Name) assert.Equal(t, constants.FluxSystem, helmRepoMsg.ObjectMeta.Namespace) assert.Equal(t, projectID, helmRepoMsg.ObjectMeta.Labels[constants.Tenant]) default: fmt.Println("obj kind not supported") } } } } done := make(chan bool) chariotPubsubClient, err := createChariotV2TestTopic(done, assertSubscriptionMessage) assert.NoError(t, err) chariotService := NewChariotService(projectID, testChariotPubsubTopic, chariotPubsubClient) service := NewHelmService(appConfig, chariotService, nil, db, nil, nil) assert.NoError(t, service.CreateBannerHelmRepository(context.Background(), name, "test_url", nil, projectID)) assert.Error(t, service.DeleteHelmRepo(context.Background(), name, projectID, bannerEdgeID)) assert.NoError(t, service.DeleteHelmRepo(context.Background(), name, projectID, bannerEdgeID)) } func TestHelmService_GetHelmReleasesStatus(t *testing.T) { clusterName := "test_cluster2" testCluster := getTestCluster(clusterName) helm1 := getTestHelmReleaseWithStatus("helm_release_1", true) helm2 := getTestHelmReleaseWithStatus("helm_release_2", false) repo1 := getTestHelmRepository("helm_release_1") repo2 := getTestHelmRepository("helm_release_2") srv := createHelmRepoClient(t, map[string][]byte{}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, helmSecret, *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } getKubeResource := func(_ context.Context, _projectID string, cluster *model.Cluster, input model.LoqRequest) ([]string, error) { assert.Equal(t, projectID, _projectID) assert.Equal(t, clusterName, cluster.Name) assert.Contains(t, []model.LoqRequest{mapper.GetHelmReleases()}, input) if input == mapper.GetHelmRepositories() { res1, err := json.Marshal(repo1) assert.NoError(t, err) res2, err := json.Marshal(repo2) assert.NoError(t, err) return []string{string(res1), string(res2)}, err } res1, err := json.Marshal(helm1) assert.NoError(t, err) res2, err := json.Marshal(helm2) assert.NoError(t, err) return []string{string(res1), string(res2)}, err } gcpService := createGCPServiceMock(t, getSecret) bqClientMock := createMockBQClient(t, getKubeResource) service := NewHelmService(appConfig, nil, gcpService, nil, bqClientMock, nil) releases, err := service.GetHelmReleasesStatus(context.Background(), testCluster) assert.NoError(t, err) assert.Len(t, releases, 2) h1 := releases[0] assert.Equal(t, "helm_release_1", h1.Name) assert.Equal(t, "Succeeded", h1.StatusType) assert.Nil(t, h1.InstallCondition) assert.NotNil(t, h1.ReadyCondition) h2 := releases[1] assert.Equal(t, "helm_release_2", h2.Name) assert.Equal(t, "Failed", h2.StatusType) assert.NotNil(t, h2.InstallCondition) assert.Nil(t, h2.ReadyCondition) for _, release := range releases { assert.NotEmpty(t, release.LastActionTime) assert.Equal(t, chartVersion, release.VersionInstalled) assert.Equal(t, chartVersion, release.VersionRequested) assert.NotNil(t, release.ConfigValues) } } func TestSendExternalSecretToChariot(t *testing.T) { testExternalSecretOne := externalsecrets.DefaultExternalSecret(). Name("test-ext-scrt-1"). Namespace("default"). ProjectID(projectID). Path(chariotPath) testExternalSecretTwo := externalsecrets.DefaultExternalSecret(). Name("test-ext-scrt-2"). Namespace("default"). ProjectID(projectID). Path(chariotPath) testExternalSecretOneBuilt, err := testExternalSecretOne.Build() assert.NoError(t, err) externalSecretOneByte, err := json.Marshal(testExternalSecretOneBuilt) assert.NoError(t, err) testExternalSecretTwoBuilt, err := testExternalSecretTwo.Build() assert.NoError(t, err) externalSecretTwoByte, err := json.Marshal(testExternalSecretTwoBuilt) assert.NoError(t, err) assertFunc := func(message *pubSub.Message) { msg := &chariotAPI.ChariotMessage{} err := json.Unmarshal(message.Data, msg) if err != nil { fmt.Println(err) } assert.Equal(t, msg.Operation, chariotAPI.Create.String()) assert.Equal(t, msg.Owner, ComponentOwner) assert.Equal(t, len(msg.Objects), 2) for _, obj := range msg.Objects { externalSrtByte, err := base64.StdEncoding.DecodeString(obj) assert.NoError(t, err) assert.True(t, (string(externalSrtByte) == string(externalSecretOneByte)) || (string(externalSrtByte) == string(externalSecretTwoByte))) } } done := make(chan bool) chariotPubsubClient, err := createChariotV2TestTopic(done, assertFunc) assert.NoError(t, err) chariotService := NewChariotService(projectID, testChariotPubsubTopic, chariotPubsubClient) assert.NoError(t, err) service := NewHelmService(appConfig, chariotService, nil, nil, nil, nil) externalSecrets := []*externalsecrets.ExternalSecret{ testExternalSecretOne, testExternalSecretTwo, } err = service.SendExternalSecretToChariot(context.Background(), projectID, "test-org", externalSecrets) assert.NoError(t, err) <-done } func TestGenerateHelmReleaseExternalSecretsWithExternalSecrets(t *testing.T) { helmReleasName := "helm-release-with-external-secret" clusterName := "test-cluster" testSecret1 := "test-secret-1" testSecret2 := "test-secret-2" testCluster := getTestCluster(clusterName) clusterEdgeID := &testCluster.ClusterEdgeID payload := getHelmPayload(nil, clusterEdgeID, helmReleasName, jsonConfig, testSecret1, testSecret2) getSecret := func(_ context.Context, _ *string, _, _ *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.True(t, getValues) assert.Equal(t, testCluster.ProjectID, _projectID) return generateSecrets(testCluster.ProjectID, payload.Secrets), nil } gcpService := createGCPServiceMock(t, getSecret) chariotService := NewChariotService(projectID, testChariotPubsubTopic, nil) service := NewHelmService(appConfig, chariotService, gcpService, nil, nil, nil) externalSecrets, err := service.GenerateHelmReleaseExternalSecrets(context.Background(), testCluster.ProjectID, payload.Namespace, []string{testSecret1, testSecret2}) assert.NoError(t, err) assert.NotEmpty(t, externalSecrets) } func TestGenerateHelmReleaseExternalSecrets(t *testing.T) { dp := externalsecrets.DockerPullSecretType res := createExternalSecretByType(projectID, namespace, &model.SecretManagerResponse{ Name: "docker-pull", Project: projectID, Values: []*model.KeyValuesOutput{{ Key: "dockerconfigjson", Value: "config", }}, Type: &dp, }) sec, err := res.Build() assert.NoError(t, err) assert.Equal(t, "dockerconfigjson", sec.Spec.Data[0].SecretKey) } func generateSecrets(projectID string, secrets []string) []*model.SecretManagerResponse { secretResp := make([]*model.SecretManagerResponse, 0) for _, name := range secrets { secretResp = append(secretResp, getSecretManagerResponse(name, projectID, "test_helmUrl", helmRepoSecretType)) } dp := externalsecrets.DockerPullSecretType secretResp = append(secretResp, &model.SecretManagerResponse{ Name: "docker-pull", Project: projectID, Values: []*model.KeyValuesOutput{{ Key: ".dockerconfigjson", Value: "config", }}, Type: &dp, }) return secretResp } func TestHelmService_GetHelmCharts(t *testing.T) { srv := createHelmRepoClient(t, map[string][]byte{}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, helmSecret, *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil) helmCharts, err := service.GetHelmCharts(context.Background(), helmSecret, projectID) assert.NoError(t, err) assert.Len(t, helmCharts, 2) actual := funk.Find(helmCharts, func(chart *model.HelmChart) bool { return chart.Name == chartName }).(*model.HelmChart) expected := getHelmManifestResponse(srv.URL).Entries[chartName][0] assert.Equal(t, expected.Name, actual.Name) assert.Equal(t, expected.Description, actual.Description) assert.Equal(t, expected.Version, actual.Version) assert.Equal(t, expected.AppVersion, actual.AppVersion) assert.Equal(t, expected.Icon, actual.Icon) assert.Equal(t, expected.Keywords, actual.Keywords) assert.Equal(t, expected.Sources, actual.Sources) } func TestHelmService_GetHelmChartVersion(t *testing.T) { srv := createHelmRepoClient(t, map[string][]byte{}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, helmSecret, *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil) helmVersions, err := service.GetHelmChartVersion(context.Background(), chartName, helmSecret, projectID) assert.NoError(t, err) assert.Len(t, helmVersions.Versions, 2) versions := funk.Map(helmVersions.Versions, func(s *string) string { return *s }).([]string) assert.Contains(t, []string{chartVersion, "1.1"}, versions[0]) assert.Contains(t, []string{chartVersion, "1.1"}, versions[1]) } func TestHelmService_GetDefaultConfigSchema(t *testing.T) { params := getHelmConfigSchemaParams() configValueURL := fmt.Sprintf("/%s-%s/values.yaml", params.ChartName, params.ChartVersion) schemaURL := fmt.Sprintf("/%s-%s/values.schema.json", params.ChartName, params.ChartVersion) srv := createHelmRepoClient(t, map[string][]byte{configValueURL: []byte(configValue), schemaURL: []byte(configSchema)}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, helmSecret, *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil) helmConfig, err := service.GetDefaultConfigSchema(context.Background(), params.ChartName, params.SecretName, params.ChartVersion, projectID) assert.NoError(t, err) assert.NotNil(t, helmConfig) assert.NotEmpty(t, helmConfig.ConfigVals) assert.Equal(t, *helmConfig.ConfigVals, `# The pod name Name: my-alpine `) } func TestHelmService_GetHelmRepositoryInfo(t *testing.T) { params := getHelmConfigSchemaParams() url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion) srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, helmSecret, *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil) repoInfo, err := service.GetHelmRepositoryInfo(context.Background(), params, projectID) assert.NoError(t, err) assert.NotNil(t, repoInfo) assert.Nil(t, repoInfo.Metadata) assert.NotEmpty(t, repoInfo.Readme) } func TestHelmService_GetHelmWorkloads(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) helmEdgeID := "be8536ff-d463-4aff-8fa9-fe81fec1ddc1" clusterEdgeID := testClusterEdgeID bannerEdgeID := testBannerEdgeID if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() params := getHelmConfigSchemaParams() url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion) srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, "test-helm-workload", *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) secret := &model.HelmSecrets{ SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642", Name: "test-secret2", CreatedAt: "2022-10-19 17:33:07.347283+00", UpdatedAt: "2022-10-19 17:33:07.347283+00", } helmWorkload := getTestHelmWorkloadQuery() service := NewHelmService(appConfig, nil, gcpService, db, nil, nil) type test struct { testName string clusterEdgeID string bannerEdgeID string expectedCount int mockSQLQueries []func() *sqlmock.ExpectedQuery } tests := []test{ {testName: "GetHelmWorkloadsByClusterEdgeID", clusterEdgeID: clusterEdgeID, bannerEdgeID: bannerEdgeID, expectedCount: 1, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID). WithArgs(clusterEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}). AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID). WithArgs(helmEdgeID). WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}). AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type")) }, }, }, {testName: "GetHelmWorkloadsByBannerEdgeID", clusterEdgeID: "", bannerEdgeID: bannerEdgeID, expectedCount: 1, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID). WithArgs(bannerEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}). AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID). WithArgs(helmEdgeID). WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}). AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type")) }, }, }, } for _, tc := range tests { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { var response []*model.HelmWorkload var err error if tc.testName == "GetHelmWorkloadsByClusterEdgeID" { response, err = service.GetHelmWorkloads(context.Background(), &clusterEdgeID, &bannerEdgeID, true) } else { var emptyClusterEdgeID *string response, err = service.GetHelmWorkloads(context.Background(), emptyClusterEdgeID, &bannerEdgeID, true) } responseMap := make(map[string]bool, 0) for i := 0; i < len(response); i++ { if responseMap[response[i].HelmEdgeID] == true { assert.Fail(t, fmt.Sprintf("duplicate helm release returned: %s", response[i].Name)) } else { responseMap[response[i].HelmEdgeID] = true } } assert.NoError(t, err) assert.Equal(t, len(response), tc.expectedCount) assert.Equal(t, len(response[0].Configmaps), 1) assert.Equal(t, response[0].Configmaps[0].ConfigMap, "config_map") }) } t.Run("GetHelmWorkloadsFailureScenario", func(t *testing.T) { var emptyClusterEdgeID *string var emptyBannerEdgeID *string _, err := service.GetHelmWorkloads(context.Background(), emptyClusterEdgeID, emptyBannerEdgeID, true) assert.EqualError(t, err, "please provide clusterEdgeId or bannerEdgeId") }) } func TestHelmService_GetAttachedHelmSecrets(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) helmEdgeID := "be8536ff-d463-4aff-8fa9-fe81fec1ddc1" if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() secret := &model.HelmSecrets{ SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642", Name: "test-secret2", CreatedAt: "2022-10-19 17:33:07.347283+00", UpdatedAt: "2022-10-19 17:33:07.347283+00", } mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID). WithArgs("be8536ff-d463-4aff-8fa9-fe81fec1ddc1"). WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}). AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt)) mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at")) mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID). WithArgs(helmEdgeID). WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}). AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type")) service := NewHelmService(appConfig, nil, nil, db, nil, nil) response, err := service.GetAttachedHelmSecrets(context.Background(), &helmEdgeID) assert.NoError(t, err) assert.Equal(t, len(response), 1) } func TestHelmService_GetHelmWorkloadsData(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) clusterEdgeID := testClusterEdgeID bannerEdgeID := testBannerEdgeID if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() helmWorkload := getTestHelmWorkloadQuery() mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID). WithArgs(clusterEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) service := NewHelmService(appConfig, nil, nil, db, nil, nil) response, err := service.GetHelmWorkloadsData(context.Background(), &clusterEdgeID, &bannerEdgeID, true) assert.NoError(t, err) assert.Equal(t, len(response), 1) } func TestHelmService_checkNamespaceToDelete(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) clusterEdgeID := testClusterEdgeID bannerEdgeID := testBannerEdgeID if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() var helmWorkload = getTestHelmWorkloadQuery() service := NewHelmService(appConfig, nil, nil, db, nil, nil) type test struct { testName string clusterEdgeID string workloadName string want bool mockSQLQuery func() *sqlmock.ExpectedQuery } tests := []test{ //case1: namespace used on only one workload, isDeleteNamespace should be true {testName: "deleteNamespace", clusterEdgeID: clusterEdgeID, workloadName: helmWorkload.Name, want: true, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID). WithArgs(clusterEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) }, }, //case2: namespace used on two workloads, isDeleteNamespace should be false {testName: "notDeleteNamespace", clusterEdgeID: clusterEdgeID, workloadName: helmWorkload.Name, want: false, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID). WithArgs(clusterEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "banner_edge_id", "helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow(clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false). AddRow(clusterEdgeID, bannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, false)) }, }, } for i, tc := range tests { tc.mockSQLQuery() t.Run(tc.testName, func(t *testing.T) { workload, isDeleteNamespace, err := service.checkNamespaceToDelete(context.Background(), &tests[i].clusterEdgeID, tc.workloadName) assert.Equal(t, tc.workloadName, workload.Name) assert.Equal(t, tc.want, isDeleteNamespace) assert.NoError(t, err) }) } } func TestHelmService_addSecretsToDeleteToChariotMessage(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) clusterEdgeID := testClusterEdgeID if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() defaultValue := "" helmWorkload := &model.HelmWorkload{ HelmEdgeID: "be8536ff-d463-4aff-8fa9-fe81fec1ddc1", Name: "test-helm-workload", Namespace: "nginx", HelmChart: "nginx", HelmRepository: "test-repo", HelmChartVersion: "2.3.1", ConfigValues: &defaultValue, InstalledBy: &defaultValue, HelmRepoSecret: "test-helm-workload", } service := NewHelmService(appConfig, nil, nil, db, nil, nil) type test struct { testName string clusterEdgeID string workload *model.HelmWorkload messageLength int want []string mockSQLQuery func() *sqlmock.ExpectedQuery } tests := []test{ //case1: one oecret {testName: "oneSecret", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 2, want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0IiwibmFtZXNwYWNlIjoibmdpbngiLCJjcmVhdGlvblRpbWVzdGFtcCI6bnVsbH0sInNwZWMiOnsic2VjcmV0U3RvcmVSZWYiOnsibmFtZSI6IiJ9LCJ0YXJnZXQiOnt9fSwic3RhdHVzIjp7InJlZnJlc2hUaW1lIjpudWxsLCJiaW5kaW5nIjp7fX19"}, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID). WithArgs(clusterEdgeID, helmWorkload.Namespace). WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret)) }, }, //case2: two secrets {testName: "twoSecrets", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 3, want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0IiwibmFtZXNwYWNlIjoibmdpbngiLCJjcmVhdGlvblRpbWVzdGFtcCI6bnVsbH0sInNwZWMiOnsic2VjcmV0U3RvcmVSZWYiOnsibmFtZSI6IiJ9LCJ0YXJnZXQiOnt9fSwic3RhdHVzIjp7InJlZnJlc2hUaW1lIjpudWxsLCJiaW5kaW5nIjp7fX19", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0MiIsIm5hbWVzcGFjZSI6Im5naW54IiwiY3JlYXRpb25UaW1lc3RhbXAiOm51bGx9LCJzcGVjIjp7InNlY3JldFN0b3JlUmVmIjp7Im5hbWUiOiIifSwidGFyZ2V0Ijp7fX0sInN0YXR1cyI6eyJyZWZyZXNoVGltZSI6bnVsbCwiYmluZGluZyI6e319fQ=="}, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID). WithArgs(clusterEdgeID, helmWorkload.Namespace). WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2")) }, }, //case3: one of two secrets use both use in another workload {testName: "twoSecretsBothUsed1", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 2, want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0MiIsIm5hbWVzcGFjZSI6Im5naW54IiwiY3JlYXRpb25UaW1lc3RhbXAiOm51bGx9LCJzcGVjIjp7InNlY3JldFN0b3JlUmVmIjp7Im5hbWUiOiIifSwidGFyZ2V0Ijp7fX0sInN0YXR1cyI6eyJyZWZyZXNoVGltZSI6bnVsbCwiYmluZGluZyI6e319fQ=="}, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID). WithArgs(clusterEdgeID, helmWorkload.Namespace). WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2"). AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, externalSecret)) }, }, //case4: two secrets both use in another workload {testName: "twoSecretsBothUsed2", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 1, want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319"}, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID). WithArgs(clusterEdgeID, helmWorkload.Namespace). WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret). AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2"). AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, externalSecret). AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, "ExternalSecret2")) }, }, } for _, tc := range tests { tc.mockSQLQuery() t.Run(tc.testName, func(t *testing.T) { var message []string installationType := model.WorkloadInstallationTypeServerPreferred helmRelease, err := mapper.ToCreateHelmReleaseBase64String(helmWorkload.Name, "", "", "", "", "", []byte{}, installationType, nil, "latest", "") assert.NoError(t, err) message = append(message, helmRelease) message, err = service.addSecretsToDeleteToChariotMessage(context.Background(), helmWorkload, clusterEdgeID, message) assert.Equal(t, tc.want, message) assert.Equal(t, len(message), tc.messageLength) assert.NoError(t, err) }) } } // Unit test for parseRepoURLYaml func TestParseRepoURLYaml(t *testing.T) { jsn := getHelmManifestResponse("ip") response, _ := yaml.Marshal(&jsn) _, err := parseRepoURLYaml(response) if err != nil { t.Fatalf(`Got error %v`, err) } } func TestGetWorkloadsByName(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) var ( helmEdgeID = helmEdgeID clusterEdgeID = testClusterEdgeID workloadName = "test-workload-name" ) testCases := []struct { title string helmEdgeID *string workloadName string clusterEdgeID string mockSQLQuery func() *sqlmock.ExpectedQuery }{ { title: "GetHelmWorkloadsByNameAndID", workloadName: workloadName, clusterEdgeID: clusterEdgeID, // mockSQLQuery: func() *sqlmock.ExpectedExec { // return mock.ExpectQuery(sqlquery.GetWorkloadsByNameAndID). // WithArgs(helmEdgeID). // WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "", ""}). // AddRow(workloadName, helmEdgeID, clusterEdgeID)) // }, mockSQLQuery: func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetWorkloadsByNameAndID). WithArgs(clusterEdgeID, workloadName). WillReturnRows(sqlmock.NewRows([]string{"workload_name", "helm_edge_id", "cluster_edge_id"}). AddRow(workloadName, helmEdgeID, clusterEdgeID)) }, }, } for _, tc := range testCases { tc.mockSQLQuery() t.Run(tc.title, func(t *testing.T) { helmWorkloads, err := service.GetHelmWorkloadsByName(context.Background(), tc.clusterEdgeID, tc.workloadName) assert.NoError(t, err) assert.NotEmpty(t, helmWorkloads) }) } } func TestSoftDeleteHelmReleaseSQLEntry(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) var ( helmEdgeID = helmEdgeID clusterEdgeID = testClusterEdgeID //workloadName = "test-workload-name" ) testCases := []struct { title string helmEdgeID *string workloadName *string clusterEdgeID *string mockSQLQueries []func() *sqlmock.ExpectedQuery mockSQLExec func() *sqlmock.ExpectedExec expectErr bool }{ { title: "Pass in helmEdgeID only", helmEdgeID: &helmEdgeID, workloadName: nil, clusterEdgeID: nil, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetClusterEdgeIDsUsingHelmWorkloadLabels). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id"}). AddRow(clusterEdgeID)) }, }, mockSQLExec: func() *sqlmock.ExpectedExec { return mock.ExpectExec(sqlquery.DeleteHelmWorkload).WithArgs(helmEdgeID). WillReturnResult(sqlmock.NewResult(1, 1)) }, expectErr: true, }, { title: "Pass in nil only", helmEdgeID: nil, workloadName: nil, clusterEdgeID: nil, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return nil }, }, mockSQLExec: func() *sqlmock.ExpectedExec { return nil }, expectErr: true, }, } for _, tc := range testCases { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } tc.mockSQLExec() t.Run(tc.title, func(t *testing.T) { err := service.SoftDeleteHelmReleaseSQL(context.Background(), tc.helmEdgeID, tc.workloadName, tc.clusterEdgeID) if tc.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestUpdateHelmReleaseSQLEntry(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) username := "test-user" version := "1.2.2" configValues := "configValues" helmEdgeID := "aa46d745-adf3-4482-955d-c046178a67ea" namespace := "test-ns" now := time.Now() ctx := middleware.NewContext(context.Background(), &types.AuthUser{ Username: "test-user", }) type testCase struct { title string version *string configValues *string configMaps []model.InjectableConfigmaps mockSQLQueries func() []interface{} } testCases := []testCase{ { title: "Version and config values are provided, no config map(s) selected", version: &version, configValues: &configValues, configMaps: nil, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)), mock.ExpectExec(sqlquery.DeleteHelmConfigmaps).WithArgs(helmEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)), } }, }, { title: "Version and config values are not provided, no config map(s) selected", version: nil, configValues: nil, configMaps: nil, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectQuery(sqlquery.GetHelmWorkloadInfoByHelmEdgeID).WithArgs(helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"helm_chart_version", "helm_config"}).AddRow(version, configValues)), mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)), mock.ExpectExec(sqlquery.DeleteHelmConfigmaps).WithArgs(helmEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)), } }, }, { title: "Version and config values are provided, EdgeInfo and BSLInfo config maps selected", version: &version, configValues: &configValues, configMaps: []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo, model.InjectableConfigmapsBSLInfo}, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)), mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).WithArgs(helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"})), mock.ExpectBegin(), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsEdgeInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsBSLInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectCommit(), } }, }, { title: "Version and config values are provided, EdgeInfo config map selected and BSLInfo config map deselected", version: &version, configValues: &configValues, configMaps: []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo}, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)), mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).WithArgs(helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("test-edge-id", helmEdgeID, namespace, model.InjectableConfigmapsBSLInfo.String(), now, now)), mock.ExpectBegin(), mock.ExpectExec(sqlquery.DeleteHelmConfigmap).WithArgs(helmEdgeID, model.InjectableConfigmapsBSLInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsEdgeInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectCommit(), } }, }, } for _, tc := range testCases { tc.mockSQLQueries() t.Run(tc.title, func(t *testing.T) { err := service.UpdateHelmReleaseSQL(ctx, helmEdgeID, tc.version, tc.configValues, tc.configMaps) assert.NoError(t, err) assert.NoError(t, mock.ExpectationsWereMet()) }) } } func TestCreateHelmReleaseSQLEntry(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) // When the installtion type is not defined in the payload, this should be the default installation type defaultInstallationType := model.WorkloadInstallationTypeServerPreferred name := "hr-name" configValues := "configValues" secrets := []string{"secret1", "secret2"} cluster := getTestCluster("test-cluster") hrPayload := getHelmPayload(&cluster.BannerEdgeID, &cluster.ClusterEdgeID, name, configValues, secrets...) hrPayloadNoBanner := getHelmPayload(nil, &cluster.ClusterEdgeID, name, configValues, secrets...) hrPayloadNoCluster := getHelmPayload(&cluster.BannerEdgeID, nil, name, configValues, secrets...) hrPayloadNoIDs := getHelmPayload(nil, nil, name, configValues, secrets...) ctx := middleware.NewContext(context.Background(), &types.AuthUser{ Username: "test-user", }) type testCase struct { title string expectErr bool payload model.HelmReleasePayload cluster *model.Cluster mockSQLQueries func() []interface{} } testCases := []testCase{ { title: "HelmReleasePayload has both bannerEdgeID and clusterEdgeID", expectErr: false, payload: hrPayload, cluster: cluster, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectBegin(), mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(*hrPayload.BannerEdgeID, hrPayload.Name, hrPayload.Namespace, hrPayload.HelmChart, hrPayload.HelmRepository, hrPayload.Version, *hrPayload.ConfigValues, "test-user", defaultInstallationType, hrPayload.Secret). WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)), mock.ExpectExec(sqlquery.CreateWorkloadClusterMapper).WithArgs(helmEdgeID, *hrPayload.ClusterEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayload.Namespace, hrPayload.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectCommit(), } }, }, { // If the payload does not have a clusterEdgeID, the cluster model will also be nil title: "HelmReleasePayload only has bannerEdgeID", expectErr: false, payload: hrPayloadNoCluster, cluster: nil, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectBegin(), mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(*hrPayloadNoCluster.BannerEdgeID, hrPayloadNoCluster.Name, hrPayloadNoCluster.Namespace, hrPayloadNoCluster.HelmChart, hrPayloadNoCluster.HelmRepository, hrPayloadNoCluster.Version, *hrPayloadNoCluster.ConfigValues, "test-user", defaultInstallationType, hrPayloadNoCluster.Secret). WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayloadNoCluster.Namespace, hrPayloadNoCluster.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectCommit(), } }, }, { title: "HelmReleasePayload only has clusterEdgeID", expectErr: false, payload: hrPayloadNoBanner, cluster: cluster, mockSQLQueries: func() []interface{} { return []interface{}{ mock.ExpectBegin(), mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(cluster.BannerEdgeID, hrPayloadNoBanner.Name, hrPayloadNoBanner.Namespace, hrPayloadNoBanner.HelmChart, hrPayloadNoBanner.HelmRepository, hrPayloadNoBanner.Version, *hrPayloadNoBanner.ConfigValues, "test-user", defaultInstallationType, hrPayloadNoBanner.Secret). WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)), mock.ExpectExec(sqlquery.CreateWorkloadClusterMapper).WithArgs(helmEdgeID, *hrPayloadNoBanner.ClusterEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayloadNoBanner.Namespace, hrPayloadNoBanner.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)), mock.ExpectCommit(), } }, }, { title: "HelmReleasePayload does not have bannerEdgeID nor clusterEdgeID", expectErr: true, payload: hrPayloadNoIDs, cluster: nil, mockSQLQueries: func() []interface{} { return nil }, }, } for _, tc := range testCases { tc.mockSQLQueries() t.Run(tc.title, func(t *testing.T) { err := service.CreateHelmReleaseSQL(ctx, tc.payload, tc.cluster) if tc.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.NoError(t, mock.ExpectationsWereMet()) } }) } } func TestHelmService_GetHelmWorkload(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() params := getHelmConfigSchemaParams() url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion) srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)}) getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) { assert.Equal(t, "test-helm-workload", *name) assert.Nil(t, owner) assert.Equal(t, helmRepoSecretType, *_type) assert.True(t, getValues) assert.Equal(t, projectID, _projectID) return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil } gcpService := createGCPServiceMock(t, getSecret) secret := &model.HelmSecrets{ SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642", Name: "test-secret2", CreatedAt: "2022-10-19 17:33:07.347283+00", UpdatedAt: "2022-10-19 17:33:07.347283+00", } defaultValue := "" deleted := false helmWorkload := helmTypes.HelmWorkloadQuery{ ClusterEdgeID: testClusterEdgeID, BannerEdgeID: testBannerEdgeID, HelmEdgeID: helmEdgeID, Name: "test-helm-workload", Namespace: "nginx", HelmChart: "nginx", HelmRepository: "test-repo", HelmChartVersion: "2.3.1", HelmConfig: &defaultValue, InstalledBy: &defaultValue, WorkloadInstallationType: "mockInstallationType", CreatedAt: "mockCreatedAt", UpdatedAt: "mockUpdatedAt", HelmRepoSecret: "test-helm-workload", ProjectID: "test-org", Deleted: &deleted, } service := NewHelmService(appConfig, nil, gcpService, db, nil, nil) mock.ExpectQuery(sqlquery.GetHelmWorkload). WithArgs(helmEdgeID, testClusterEdgeID). WillReturnRows(sqlmock.NewRows([]string{"clusters.cluster_edge_id", "helm_workloads.banner_edge_id", "helm_workloads.helm_edge_id", "workload_name", " workload_namespace", "helm_chart", "helm_repo", "helm_chart_version", "helm_config", "installed_by", "workload_installation_type", "created_at", "updated_at", "helm_repo_secret", "project_id", "deleted"}). AddRow( helmWorkload.ClusterEdgeID, helmWorkload.BannerEdgeID, helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, helmWorkload.HelmChart, helmWorkload.HelmRepository, helmWorkload.HelmChartVersion, helmWorkload.HelmConfig, helmWorkload.InstalledBy, helmWorkload.WorkloadInstallationType, helmWorkload.CreatedAt, helmWorkload.UpdatedAt, helmWorkload.HelmRepoSecret, helmWorkload.ProjectID, helmWorkload.Deleted)) mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID). WithArgs(helmWorkload.HelmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}). AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt)) mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmWorkload.HelmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at")) mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID). WithArgs(helmWorkload.HelmEdgeID). WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}). AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type")) response, err := service.GetHelmWorkload(context.Background(), helmEdgeID, testClusterEdgeID) assert.NoError(t, err) assert.NoError(t, mock.ExpectationsWereMet()) assert.Equal(t, "test-helm-workload", response.Name) } func TestHelmService_GetHelmWorkloadConfigmaps(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) clusterEdgeID := testClusterEdgeID testHelmEdgeID := helmEdgeID if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(appConfig, nil, nil, db, nil, nil) type test struct { testName string clusterEdgeID *string helmEdgeID string expectedCount int mockSQLQueries []func() *sqlmock.ExpectedQuery } tests := []test{ {testName: "GetHelmworkloadConfigMapCountOne", clusterEdgeID: &clusterEdgeID, helmEdgeID: testHelmEdgeID, expectedCount: 1, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}). AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at")) }, }, }, {testName: "GetHelmworkloadConfigMapCountZero", clusterEdgeID: &clusterEdgeID, helmEdgeID: testHelmEdgeID, expectedCount: 0, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps). WithArgs(helmEdgeID). WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"})) }, }, }, } for _, tc := range tests { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { response, err := service.GetHelmWorkloadConfigmaps(context.Background(), tc.helmEdgeID) assert.NoError(t, err) assert.Equal(t, tc.expectedCount, len(response)) if tc.expectedCount == 0 { emptyConfigMapList := make([]*model.HelmWorkloadConfigmaps, 0) assert.Equal(t, emptyConfigMapList, response) } }) } } func TestHelmService_DeleteHelmWorkloadSecrets(t *testing.T) { testSecretNames := []string{"test-secret-02"} testHelmID := helmEdgeID db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectExec(sqlquery.DeleteHelmSecret).WithArgs(testHelmID, testSecretNames[0]). WillReturnResult(sqlmock.NewResult(1, 1)) service := NewHelmService(appConfig, nil, nil, db, nil, nil) if _, err = service.DeleteHelmSecrets(context.Background(), testHelmID, testSecretNames); err != nil { t.Errorf("error deleting secrets: %s", err) } assert.NoError(t, err) if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } } func TestHelmService_GetHelmStatus(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() ctx := middleware.NewContext(context.Background(), &types.AuthUser{ Username: "test-user", }) workloadName := "test-helm-release" workloadNamespace := "test-helm-release-ns" helmChartName := "test-chart" helmRepoName := "test-repository" testCluster := "test-cluster-123" updatedTime, _ := time.Parse(time.RFC3339, "2024-01-01T01:00:00.000000-00:00") service := NewHelmService(nil, nil, nil, db, nil, nil) type test struct { testName string clusterEdgeID string createdAt string updatedAt string expected *model.HelmStatus mockSQLQueries []func() *sqlmock.ExpectedQuery } tests := []test{{ testName: "successful-helm-release", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-01T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Ready, Message: status.WorkloadReadyStatusMessage, Pods: []*model.Pods{ {Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"}, {Name: "test-helm-pod2", Status: status.Running, Message: "Pod is ready"}, }, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "\"True\"", "false"). AddRow("test-helm-pod2", "\"True\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "", "true"). AddRow("test-helm-pod2", "", "true")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"True\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRelease", workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"UpgradeSucceeded\"", "false")) }, }, }, { testName: "failed-helm-release", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-01T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Error, Message: "HelmRelease: UpgradeFailed, helmChart: Failed to get Helm Chart, helmRepo: Failed to get Helm Repo", Pods: []*model.Pods{ {Name: "test-helm-pod1", Status: status.Error, Message: "Pod Failed"}, }, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "\"False\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "Pod Failed", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRelease", workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"UpgradeFailed\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmChart", helmChartName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmChart", helmChartName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"Failed to get Helm Chart\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRepo", helmRepoName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRepo", helmRepoName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"Failed to get Helm Repo\"", "false")) }, }, }, { testName: "installing-helm-release", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-01T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Installing, Message: status.InstallingStatusMessage, Pods: []*model.Pods{}, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"})) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"})) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime)) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"\"", "true")) }, }, }, { testName: "installing-helm-release-no-watched-entry", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-01T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Installing, Message: status.InstallingStatusMessage, Pods: []*model.Pods{}, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"})) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"})) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"})) }, }, }, { testName: "updating-helm-release", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-02T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Updating, Message: status.UpdatingStatusMessage, Pods: []*model.Pods{ {Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"}, {Name: "test-helm-pod2", Status: status.Error, Message: "Pod Failed"}, }, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "\"True\"", "false"). AddRow("test-helm-pod2", "\"False\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "", "true"). AddRow("test-helm-pod2", "Pod Failed", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime)) }, }, }, { testName: "updating-helm-release-no-watched-entry", clusterEdgeID: testCluster, createdAt: "2024-01-01T01:00:00.000000-00:00", updatedAt: "2024-01-02T01:00:00.000000-00:00", expected: &model.HelmStatus{ Status: status.Updating, Message: status.UpdatingStatusMessage, Pods: []*model.Pods{ {Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"}, {Name: "test-helm-pod2", Status: status.Running, Message: "Pod is ready"}, }, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "\"True\"", "false"). AddRow("test-helm-pod2", "\"True\"", "false")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace). WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}). AddRow("test-helm-pod1", "", "true"). AddRow("test-helm-pod2", "", "true")) }, func() *sqlmock.ExpectedQuery { return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster). WillReturnRows(mock.NewRows([]string{"watched_at"})) }, }, }, } for _, tc := range tests { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { combinedStatus, err := service.GetHelmStatus(ctx, testCluster, workloadName, workloadNamespace, helmChartName, helmRepoName, tc.createdAt, tc.updatedAt, &falseValue) assert.NoError(t, err) assert.Equal(t, tc.expected.Status, combinedStatus.Status) assert.Equal(t, tc.expected.Message, combinedStatus.Message) assert.Equal(t, len(tc.expected.Pods), len(combinedStatus.Pods)) for _, pod1 := range tc.expected.Pods { for _, pod2 := range combinedStatus.Pods { if pod1.Name == pod2.Name { assert.Equal(t, pod1.Status, pod2.Status) assert.Equal(t, pod1.Message, pod2.Message) } } } }) } } func TestHelmService_GetHelmStatusWithoutClusterID(t *testing.T) { db, _, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() ctx := middleware.NewContext(context.Background(), &types.AuthUser{ Username: "test-user", }) workloadName := "test-helm-release" workloadNamespace := "test-helm-release-ns" helmChartName := "test-chart" helmRepoName := "test-repository" //testCluster := "test-cluster-123" includeDeleted := false service := NewHelmService(nil, nil, nil, db, nil, nil) type test struct { testName string clusterEdgeID string createdAt string updatedAt string deleted *bool expected *model.HelmStatus mockSQLQueries []func() *sqlmock.ExpectedQuery } tests := []test{ { testName: "passing-in-empty-clusterEdgeID", clusterEdgeID: "", deleted: &includeDeleted, expected: &model.HelmStatus{ Status: status.NotAvailable, Message: status.NotDeployedStatusMessage, }, mockSQLQueries: []func() *sqlmock.ExpectedQuery{ func() *sqlmock.ExpectedQuery { return nil }, }, }, } for _, tc := range tests { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { combinedStatus, err := service.GetHelmStatus(ctx, tc.clusterEdgeID, workloadName, workloadNamespace, helmChartName, helmRepoName, tc.createdAt, tc.updatedAt, tc.deleted) assert.NoError(t, err) assert.Equal(t, tc.expected.Status, combinedStatus.Status) assert.Equal(t, tc.expected.Message, combinedStatus.Message) assert.Empty(t, combinedStatus.Pods) }) } } func TestDeleteLabelFromHelmWorkload(t *testing.T) { testHelmID := "test-helm-delete" testLabelID := "test-label-id-delete" db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) errMock := fmt.Errorf("ExecQuery 'DELETE FROM helm_workload_labels WHERE label_edge_id = $1 AND helm_edge_id=$2', arguments do not match: argument 0 expected [string - dsadadasdasdsa] does not match actual [string - jibberish]") errMsg := sqlerr.Wrap(errMock) type result struct { result bool err error } type test struct { testName string expected result testLabel string mockSQLQueries []func() *sqlmock.ExpectedExec } tests := []test{ //nolint { testName: "Delete single valid label", expected: result{ result: true, err: nil, }, testLabel: testLabelID, mockSQLQueries: []func() *sqlmock.ExpectedExec{ func() *sqlmock.ExpectedExec { testRes := mock.ExpectExec(sqlquery.DeleteLabelFromHelmWorkload).WithArgs(testLabelID, testHelmID). WillReturnResult(sqlmock.NewResult(1, 1)) return testRes }, }, }, { testName: "Delete single invalid label", expected: result{ result: false, err: errMsg, }, testLabel: "jibberish", mockSQLQueries: []func() *sqlmock.ExpectedExec{ func() *sqlmock.ExpectedExec { testRes := mock.ExpectExec(sqlquery.DeleteLabelFromHelmWorkload).WithArgs("dsadadasdasdsa", testHelmID). WillReturnResult(sqlmock.NewResult(1, 1)) return testRes }, }, }, } for _, tc := range tests { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { res, err := service.DeleteWorkloadLabel(context.Background(), testHelmID, tc.testLabel) if err != nil { assert.Error(t, err) } assert.Equal(t, tc.expected.result, res) assert.Equal(t, tc.expected.err, err) }) } } func TestAddLabelToHelmWorkload(t *testing.T) { testLabelIDForAdd := "test-label-id-add" helmWorkload := getTestHelmWorkloadQuery() db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() service := NewHelmService(nil, nil, nil, db, nil, nil) type result struct { result bool err error } type testAddWorkloadLabel struct { testName string expected result testLabel string mockSQLQueries []func() *sqlmock.ExpectedExec } errMsg := fmt.Errorf("[{\"message\":\"Invalid input syntax for type\",\"extensions\":{\"additional\":{\"errorType\":\"EDGE_SQL_STATE\",\"severity\":\"\",\"statusCode\":\"Unknown\"},\"operationID\":\"\",\"version\":\"0.20.0\"}}]") sqlErr := sqlerr.Wrap(errMsg) testAdd := []testAddWorkloadLabel{ //nolint { testName: "Add valid label", expected: result{ result: true, err: nil, }, testLabel: testLabelIDForAdd, mockSQLQueries: []func() *sqlmock.ExpectedExec{ func() *sqlmock.ExpectedExec { testRes := mock.ExpectExec(sqlquery.CreateHelmWorkloadLabels).WithArgs(helmWorkload.HelmEdgeID, testLabelIDForAdd). WillReturnResult(sqlmock.NewResult(1, 1)) return testRes }, }, }, { testName: "Add invalid label", expected: result{ result: false, err: sqlErr, }, testLabel: "", mockSQLQueries: []func() *sqlmock.ExpectedExec{ func() *sqlmock.ExpectedExec { testRes := mock.ExpectExec(sqlquery.CreateHelmWorkloadLabels).WithArgs(helmWorkload.HelmEdgeID, ""). WillReturnError(errMsg) return testRes }, }, }, } for _, tc := range testAdd { for _, mockSQLFn := range tc.mockSQLQueries { mockSQLFn() } t.Run(tc.testName, func(t *testing.T) { res, err := service.AddWorkloadLabel(context.Background(), helmWorkload.HelmEdgeID, tc.testLabel) if err != nil { assert.Error(t, err) } assert.Equal(t, tc.expected.result, res) assert.Equal(t, tc.expected.err, err) }) } } func GetBannerByHelmEdgeID(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() expectedProjectID := projectID mock.ExpectQuery(sqlquery.GetBannerByHelmEdgeID).WithArgs(helmEdgeID). WillReturnRows(mock.NewRows([]string{"project_id", "banner_edge_id"}). AddRow(expectedProjectID, bannerEdgeID)) service := NewHelmService(appConfig, nil, nil, db, nil, nil) banner, err := service.GetBannerByHelmEdgeID(context.Background(), helmEdgeID) assert.NoError(t, err) assert.Equal(t, expectedProjectID, banner.ProjectID) assert.Equal(t, bannerEdgeID, banner.BannerEdgeID) if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } } func getTestHelmReleaseWithStatus(name string, succeededStatus bool) *helmApi.HelmRelease { helmRelease := &helmApi.HelmRelease{ TypeMeta: metav1.TypeMeta{ APIVersion: helmApi.GroupVersion.String(), Kind: helmRelease, }, ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, Labels: map[string]string{ mapper.SecretManagerSecretLabel: helmSecret, }, }, Spec: helmApi.HelmReleaseSpec{ Interval: metav1.Duration{ Duration: time.Duration(2) * time.Minute, }, ReleaseName: name, TargetNamespace: ns, Chart: &helmApi.HelmChartTemplate{ Spec: helmApi.HelmChartTemplateSpec{ Chart: chartName, Version: chartVersion, SourceRef: helmApi.CrossNamespaceObjectReference{ Kind: helmRepoKind, Name: name, }, }, }, Values: &apiextensionsv1.JSON{ Raw: []byte(configValue), }, Timeout: &metav1.Duration{ Duration: time.Duration(15) * time.Minute, }, }, Status: helmApi.HelmReleaseStatus{ ObservedGeneration: 0, History: helmApi.Snapshots{ &helmApi.Snapshot{ ChartVersion: chartVersion, }, }, }, } if succeededStatus { condition := metav1.Condition{ Type: "Ready", Status: "True", LastTransitionTime: metav1.Now(), Reason: "test reason", Message: "reconciliation successful", } helmRelease.Status.Conditions = append(helmRelease.Status.Conditions, condition) } else { condition := metav1.Condition{ Type: helmApi.ReleasedCondition, Status: "False", LastTransitionTime: metav1.Now(), Reason: "test failure", Message: "install failed", } helmRelease.Status.Conditions = append(helmRelease.Status.Conditions, condition) } return helmRelease } func getTestHelmRepository(name string) *helmRepositoryApi.HelmRepository { return &helmRepositoryApi.HelmRepository{ TypeMeta: metav1.TypeMeta{ APIVersion: helmRepositoryApi.GroupVersion.String(), Kind: helmRepoKind, }, ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, CreationTimestamp: metav1.Now(), }, Spec: helmRepositoryApi.HelmRepositorySpec{ URL: helmRepoURL, SecretRef: &meta.LocalObjectReference{Name: helmSecret}, Interval: metav1.Duration{Duration: 2 * time.Minute}, }, } } func createHelmRepoClient(t *testing.T, mapping map[string][]byte) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method) mapping["/index.yaml"] = getHelmCharts(t, r.Host) mapping[".tgz"] = []byte(zippedChart) for url, response := range mapping { if strings.HasSuffix(r.URL.String(), url) { w.WriteHeader(200) _, err := w.Write(response) assert.NoError(t, err) return } } })) } func getHelmPayload(bannerEdgeID, clusterEdgeID *string, name, configValues string, secrets ...string) model.HelmReleasePayload { return model.HelmReleasePayload{ Name: name, Secret: helmSecret, HelmRepository: testHelmRepo, HelmChart: chartName, Version: chartVersion, BannerEdgeID: bannerEdgeID, ClusterEdgeID: clusterEdgeID, ConfigValues: &configValues, Namespace: ns, Secrets: secrets, InjectConfigmaps: []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo}, } } func getTestCluster(name string) *model.Cluster { return &model.Cluster{ ProjectID: projectID, Name: name, ClusterEdgeID: clusterEdgeID, BannerEdgeID: bannerEdgeID, } } func getSecretManagerResponse(name, project, URL, secretType string) *model.SecretManagerResponse { //nolint var testKeyValues = []*model.KeyValuesOutput{ { Key: constants.HelmUsername, Value: "test_username", }, { Key: constants.HelmPassword, Value: "test_password", }, { Key: constants.HelmURL, Value: URL, }, { Key: constants.HelmRepoName, Value: name, }, } return &model.SecretManagerResponse{ Name: name, Project: project, Values: testKeyValues, Type: &secretType, } } func getHelmCharts(t *testing.T, url string) []byte { hmr := getHelmManifestResponse(url) res, err := yaml.Marshal(&hmr) assert.NoError(t, err) return res } func getHelmManifestResponse(host string) repo.IndexFile { return repo.IndexFile{ APIVersion: "v1", Entries: map[string]repo.ChartVersions{ chartName: { { Metadata: &chart.Metadata{ Description: "test description 1", Name: chartName, Version: chartVersion, AppVersion: "v1", Icon: "icon", Home: "home", Sources: []string{"source1", "source2"}, Keywords: []string{"key1", "key2"}, }, URLs: []string{"http://" + host + "/charts.tgz", "http://" + host + "/charts.tgz"}, //Created: time.Now(), }, {Metadata: &chart.Metadata{Description: "test description 2", Name: "test name 2", Version: "1.1"}}, }, "helm_chart2": { {Metadata: &chart.Metadata{Description: "test description 3", Name: "test name 3", Version: "2.0.0"}}, }, }, } } func getHelmConfigSchemaParams() model.HelmConfigSchemaParams { return model.HelmConfigSchemaParams{ SecretName: helmSecret, BannerEdgeID: bannerEdgeID, ChartName: chartName, ChartVersion: chartVersion, } } type GetSecretsFunc = func(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error) type GetKubeResourceFunc = func(ctx context.Context, projectID string, cluster *model.Cluster, input model.LoqRequest) ([]string, error) func createGCPServiceMock(t *testing.T, getSecret GetSecretsFunc) *mocks.MockGCPService { mock := gomock.NewController(t) service := mocks.NewMockGCPService(mock) service.EXPECT(). GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn(getSecret).AnyTimes() return service } func createMockBQClient(t *testing.T, getKubeResource GetKubeResourceFunc) *mocks.MockBQClient { mock := gomock.NewController(t) service := mocks.NewMockBQClient(mock) service.EXPECT(). GetKubeResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn(getKubeResource).AnyTimes() return service } func createChariotV2TestTopic(done chan bool, assertSubscriptionMessage func(message *pubSub.Message)) (option.ClientOption, error) { chariotPubsubClient, err := chariotClientApiTestutils.NewMockPubsubServer() if err != nil { return nil, err } _, err = chariotClientApiTestutils.CreateMockTopic(context.Background(), projectID, testChariotPubsubTopic, chariotPubsubClient) if err != nil { return nil, err } go func() { err := chariotClientApiTestutils.CreateMockSubscription(context.Background(), done, projectID, testChariotPubsubTopic, testChariotPubsubSubscription, 20*time.Second, "", assertSubscriptionMessage, chariotPubsubClient) if err != nil { fmt.Println(err) } }() return chariotPubsubClient, nil } func getTestHelmWorkloadQuery() helmTypes.HelmWorkloadQuery { defaultValue := "" return helmTypes.HelmWorkloadQuery{ ClusterEdgeID: testClusterEdgeID, BannerEdgeID: testBannerEdgeID, HelmEdgeID: "be8536ff-d463-4aff-8fa9-fe81fec1ddc1", Name: "test-helm-workload", Namespace: "nginx", HelmChart: "nginx", HelmRepository: "test-repo", HelmChartVersion: "2.3.1", HelmConfig: &defaultValue, InstalledBy: &defaultValue, WorkloadInstallationType: "mockInstallationType", CreatedAt: "mockCreatedAt", UpdatedAt: "mockUpdatedAt", HelmRepoSecret: "test-helm-workload", ProjectID: "test-org", } }