...

Source file src/edge-infra.dev/pkg/edge/api/services/helm_service_test.go

Documentation: edge-infra.dev/pkg/edge/api/services

     1  package services
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	pubSub "cloud.google.com/go/pubsub"
    16  	"github.com/DATA-DOG/go-sqlmock"
    17  	helmApi "github.com/fluxcd/helm-controller/api/v2"
    18  	"github.com/fluxcd/pkg/apis/meta"
    19  	helmRepositoryApi "github.com/fluxcd/source-controller/api/v1"
    20  	"github.com/golang/mock/gomock"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/thoas/go-funk"
    23  	"google.golang.org/api/option"
    24  	"helm.sh/helm/v3/pkg/chart"
    25  	"helm.sh/helm/v3/pkg/repo"
    26  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"sigs.k8s.io/yaml"
    29  
    30  	sqlerr "edge-infra.dev/pkg/edge/api/apierror/sql"
    31  	"edge-infra.dev/pkg/edge/api/bsl/types"
    32  	"edge-infra.dev/pkg/edge/api/graph/mapper"
    33  	"edge-infra.dev/pkg/edge/api/graph/model"
    34  	"edge-infra.dev/pkg/edge/api/middleware"
    35  	"edge-infra.dev/pkg/edge/api/mocks"
    36  	sqlquery "edge-infra.dev/pkg/edge/api/sql"
    37  	"edge-infra.dev/pkg/edge/api/status"
    38  	edgetypes "edge-infra.dev/pkg/edge/api/types"
    39  	helmTypes "edge-infra.dev/pkg/edge/api/types"
    40  	chariotAPI "edge-infra.dev/pkg/edge/chariot/client"
    41  	"edge-infra.dev/pkg/edge/constants"
    42  	"edge-infra.dev/pkg/edge/externalsecrets"
    43  	chariotClientApiTestutils "edge-infra.dev/test/framework/gcp/pubsub"
    44  )
    45  
    46  const (
    47  	apiVersion                    = "clusterregistry.k8s.io/v1alpha1"
    48  	bannerEdgeID                  = "banner_edge_id"
    49  	clusterEdgeID                 = "cluster_edge_id"
    50  	clusterExternalSecret         = "ClusterExternalSecret"
    51  	chartName                     = "helm_chart"
    52  	chartVersion                  = "1.0.0"
    53  	testTime                      = "2022-01-01 12:00:00"
    54  	helmSecret                    = "helm_secret"
    55  	helmRepoKind                  = "HelmRepository"
    56  	helmRepoURL                   = "https://example.com"
    57  	readme                        = `# Helm Application`
    58  	testChariotPubsubTopic        = "chariot-pubsub-topic"
    59  	testChariotPubsubSubscription = "chariot-pubsub-subscription"
    60  	testHelmRepo                  = "helm_repo"
    61  	helmRelease                   = "HelmRelease"
    62  	namespace                     = "Namespace"
    63  	externalSecret                = "ExternalSecret"
    64  	configSchema                  = `
    65  {
    66   "$id": "https://example.com/geographical-location.schema.json",
    67   "$schema": "https://json-schema.org/draft/2020-12/schema",
    68   "title": "Longitude and Latitude Values",
    69   "description": "geographical coordinates.",
    70   "required": [ "latitude", "longitude" ],
    71   "type": "object",
    72   "properties": {
    73     "latitude": {
    74       "type": "number",
    75       "minimum": -90,
    76       "maximum": 90
    77     },
    78     "longitude": {
    79       "type": "number",
    80       "minimum": -180,r
    81       "maximum": 180
    82     }
    83   }
    84  }
    85  `
    86  	configValue = `
    87  {
    88   "latitude": 50,
    89   "longitude": 30
    90  }
    91  `
    92  	helmEdgeID        = "be8536ff-d463-4aff-8fa9-fe81fec1ddc1"
    93  	testClusterEdgeID = "3396a52c-6a22-4049-9593-5a63b596a200"
    94  	testBannerEdgeID  = "3396a52c-6a22-4049-9593-5a63b596a201"
    95  )
    96  
    97  var ns = "default"
    98  var appConfig = &edgetypes.Config{Chariot: edgetypes.ChariotConfig{}}
    99  var jsonConfig = "{\"version\":10}"
   100  
   101  //go:embed testdata/alpine-0.2.0.tgz
   102  var zippedChart string
   103  
   104  func TestHelmService_CreateAndDeleteBannerHelmRepo(t *testing.T) {
   105  	name := "test-repo"
   106  
   107  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   108  	if err != nil {
   109  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   110  	}
   111  	defer db.Close()
   112  	mock.MatchExpectationsInOrder(true)
   113  
   114  	helmWorkload := getTestHelmWorkloadQuery()
   115  
   116  	mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID).
   117  		WithArgs(bannerEdgeID).
   118  		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"}).
   119  			AddRow(
   120  				helmWorkload.ClusterEdgeID,
   121  				helmWorkload.BannerEdgeID,
   122  				helmWorkload.HelmEdgeID,
   123  				helmWorkload.Name,
   124  				helmWorkload.Namespace,
   125  				helmWorkload.HelmChart,
   126  				helmWorkload.HelmRepository,
   127  				helmWorkload.HelmChartVersion,
   128  				helmWorkload.HelmConfig,
   129  				helmWorkload.InstalledBy,
   130  				helmWorkload.WorkloadInstallationType,
   131  				helmWorkload.CreatedAt,
   132  				helmWorkload.UpdatedAt,
   133  				helmWorkload.HelmRepoSecret,
   134  				helmWorkload.ProjectID, false))
   135  
   136  	mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID).
   137  		WithArgs(bannerEdgeID).
   138  		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"}).
   139  			AddRow(
   140  				helmWorkload.ClusterEdgeID,
   141  				helmWorkload.BannerEdgeID,
   142  				helmWorkload.HelmEdgeID,
   143  				helmWorkload.Name,
   144  				helmWorkload.Namespace,
   145  				helmWorkload.HelmChart,
   146  				"",
   147  				helmWorkload.HelmChartVersion,
   148  				helmWorkload.HelmConfig,
   149  				helmWorkload.InstalledBy,
   150  				helmWorkload.WorkloadInstallationType,
   151  				helmWorkload.CreatedAt,
   152  				helmWorkload.UpdatedAt,
   153  				helmWorkload.HelmRepoSecret,
   154  				helmWorkload.ProjectID, false))
   155  
   156  	assertSubscriptionMessage := func(message *pubSub.Message) {
   157  		msg := &chariotAPI.ChariotMessage{}
   158  		err := json.Unmarshal(message.Data, msg)
   159  		if err != nil {
   160  			fmt.Println(err)
   161  		}
   162  		assert.Equal(t, projectID, msg.Banner)
   163  		if len(msg.Objects) > 0 {
   164  			for _, obj := range msg.Objects {
   165  				decoded, err := base64.StdEncoding.DecodeString(obj)
   166  				assert.NoError(t, err)
   167  				res := strings.Split(string(decoded), ",")
   168  				objKind := res[0][9 : len(res[0])-1]
   169  				switch objKind {
   170  				case clusterExternalSecret:
   171  					helmRepoMsg := &helmRepositoryApi.HelmRepository{}
   172  					err = json.Unmarshal(decoded, &helmRepoMsg)
   173  					assert.NoError(t, err)
   174  					assert.Equal(t, clusterExternalSecret, helmRepoMsg.Kind)
   175  					assert.Equal(t, name, helmRepoMsg.ObjectMeta.Name)
   176  					assert.Equal(t, constants.FluxSystem, helmRepoMsg.ObjectMeta.Namespace)
   177  					assert.Equal(t, projectID, helmRepoMsg.ObjectMeta.Labels[constants.Tenant])
   178  				default:
   179  					fmt.Println("obj kind not supported")
   180  				}
   181  			}
   182  		}
   183  	}
   184  	done := make(chan bool)
   185  	chariotPubsubClient, err := createChariotV2TestTopic(done, assertSubscriptionMessage)
   186  	assert.NoError(t, err)
   187  	chariotService := NewChariotService(projectID, testChariotPubsubTopic, chariotPubsubClient)
   188  
   189  	service := NewHelmService(appConfig, chariotService, nil, db, nil, nil)
   190  	assert.NoError(t, service.CreateBannerHelmRepository(context.Background(), name, "test_url", nil, projectID))
   191  	assert.Error(t, service.DeleteHelmRepo(context.Background(), name, projectID, bannerEdgeID))
   192  
   193  	assert.NoError(t, service.DeleteHelmRepo(context.Background(), name, projectID, bannerEdgeID))
   194  }
   195  
   196  func TestHelmService_GetHelmReleasesStatus(t *testing.T) {
   197  	clusterName := "test_cluster2"
   198  	testCluster := getTestCluster(clusterName)
   199  
   200  	helm1 := getTestHelmReleaseWithStatus("helm_release_1", true)
   201  	helm2 := getTestHelmReleaseWithStatus("helm_release_2", false)
   202  	repo1 := getTestHelmRepository("helm_release_1")
   203  	repo2 := getTestHelmRepository("helm_release_2")
   204  
   205  	srv := createHelmRepoClient(t, map[string][]byte{})
   206  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   207  		assert.Equal(t, helmSecret, *name)
   208  		assert.Nil(t, owner)
   209  		assert.Equal(t, helmRepoSecretType, *_type)
   210  		assert.True(t, getValues)
   211  		assert.Equal(t, projectID, _projectID)
   212  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   213  	}
   214  
   215  	getKubeResource := func(_ context.Context, _projectID string, cluster *model.Cluster, input model.LoqRequest) ([]string, error) {
   216  		assert.Equal(t, projectID, _projectID)
   217  		assert.Equal(t, clusterName, cluster.Name)
   218  		assert.Contains(t, []model.LoqRequest{mapper.GetHelmReleases()}, input)
   219  
   220  		if input == mapper.GetHelmRepositories() {
   221  			res1, err := json.Marshal(repo1)
   222  			assert.NoError(t, err)
   223  
   224  			res2, err := json.Marshal(repo2)
   225  			assert.NoError(t, err)
   226  			return []string{string(res1), string(res2)}, err
   227  		}
   228  
   229  		res1, err := json.Marshal(helm1)
   230  		assert.NoError(t, err)
   231  
   232  		res2, err := json.Marshal(helm2)
   233  		assert.NoError(t, err)
   234  		return []string{string(res1), string(res2)}, err
   235  	}
   236  	gcpService := createGCPServiceMock(t, getSecret)
   237  	bqClientMock := createMockBQClient(t, getKubeResource)
   238  	service := NewHelmService(appConfig, nil, gcpService, nil, bqClientMock, nil)
   239  
   240  	releases, err := service.GetHelmReleasesStatus(context.Background(), testCluster)
   241  	assert.NoError(t, err)
   242  	assert.Len(t, releases, 2)
   243  
   244  	h1 := releases[0]
   245  	assert.Equal(t, "helm_release_1", h1.Name)
   246  	assert.Equal(t, "Succeeded", h1.StatusType)
   247  	assert.Nil(t, h1.InstallCondition)
   248  	assert.NotNil(t, h1.ReadyCondition)
   249  
   250  	h2 := releases[1]
   251  	assert.Equal(t, "helm_release_2", h2.Name)
   252  	assert.Equal(t, "Failed", h2.StatusType)
   253  	assert.NotNil(t, h2.InstallCondition)
   254  	assert.Nil(t, h2.ReadyCondition)
   255  
   256  	for _, release := range releases {
   257  		assert.NotEmpty(t, release.LastActionTime)
   258  		assert.Equal(t, chartVersion, release.VersionInstalled)
   259  		assert.Equal(t, chartVersion, release.VersionRequested)
   260  		assert.NotNil(t, release.ConfigValues)
   261  	}
   262  }
   263  
   264  func TestSendExternalSecretToChariot(t *testing.T) {
   265  	testExternalSecretOne := externalsecrets.DefaultExternalSecret().
   266  		Name("test-ext-scrt-1").
   267  		Namespace("default").
   268  		ProjectID(projectID).
   269  		Path(chariotPath)
   270  	testExternalSecretTwo := externalsecrets.DefaultExternalSecret().
   271  		Name("test-ext-scrt-2").
   272  		Namespace("default").
   273  		ProjectID(projectID).
   274  		Path(chariotPath)
   275  
   276  	testExternalSecretOneBuilt, err := testExternalSecretOne.Build()
   277  	assert.NoError(t, err)
   278  	externalSecretOneByte, err := json.Marshal(testExternalSecretOneBuilt)
   279  	assert.NoError(t, err)
   280  
   281  	testExternalSecretTwoBuilt, err := testExternalSecretTwo.Build()
   282  	assert.NoError(t, err)
   283  	externalSecretTwoByte, err := json.Marshal(testExternalSecretTwoBuilt)
   284  	assert.NoError(t, err)
   285  	assertFunc := func(message *pubSub.Message) {
   286  		msg := &chariotAPI.ChariotMessage{}
   287  		err := json.Unmarshal(message.Data, msg)
   288  		if err != nil {
   289  			fmt.Println(err)
   290  		}
   291  		assert.Equal(t, msg.Operation, chariotAPI.Create.String())
   292  		assert.Equal(t, msg.Owner, ComponentOwner)
   293  		assert.Equal(t, len(msg.Objects), 2)
   294  		for _, obj := range msg.Objects {
   295  			externalSrtByte, err := base64.StdEncoding.DecodeString(obj)
   296  			assert.NoError(t, err)
   297  			assert.True(t, (string(externalSrtByte) == string(externalSecretOneByte)) || (string(externalSrtByte) == string(externalSecretTwoByte)))
   298  		}
   299  	}
   300  	done := make(chan bool)
   301  	chariotPubsubClient, err := createChariotV2TestTopic(done, assertFunc)
   302  	assert.NoError(t, err)
   303  	chariotService := NewChariotService(projectID, testChariotPubsubTopic, chariotPubsubClient)
   304  	assert.NoError(t, err)
   305  	service := NewHelmService(appConfig, chariotService, nil, nil, nil, nil)
   306  	externalSecrets := []*externalsecrets.ExternalSecret{
   307  		testExternalSecretOne,
   308  		testExternalSecretTwo,
   309  	}
   310  	err = service.SendExternalSecretToChariot(context.Background(), projectID, "test-org", externalSecrets)
   311  	assert.NoError(t, err)
   312  	<-done
   313  }
   314  
   315  func TestGenerateHelmReleaseExternalSecretsWithExternalSecrets(t *testing.T) {
   316  	helmReleasName := "helm-release-with-external-secret"
   317  	clusterName := "test-cluster"
   318  	testSecret1 := "test-secret-1"
   319  	testSecret2 := "test-secret-2"
   320  	testCluster := getTestCluster(clusterName)
   321  	clusterEdgeID := &testCluster.ClusterEdgeID
   322  	payload := getHelmPayload(nil, clusterEdgeID, helmReleasName, jsonConfig, testSecret1, testSecret2)
   323  
   324  	getSecret := func(_ context.Context, _ *string, _, _ *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   325  		assert.True(t, getValues)
   326  		assert.Equal(t, testCluster.ProjectID, _projectID)
   327  		return generateSecrets(testCluster.ProjectID, payload.Secrets), nil
   328  	}
   329  	gcpService := createGCPServiceMock(t, getSecret)
   330  
   331  	chariotService := NewChariotService(projectID, testChariotPubsubTopic, nil)
   332  	service := NewHelmService(appConfig, chariotService, gcpService, nil, nil, nil)
   333  
   334  	externalSecrets, err := service.GenerateHelmReleaseExternalSecrets(context.Background(), testCluster.ProjectID, payload.Namespace, []string{testSecret1, testSecret2})
   335  	assert.NoError(t, err)
   336  	assert.NotEmpty(t, externalSecrets)
   337  }
   338  
   339  func TestGenerateHelmReleaseExternalSecrets(t *testing.T) {
   340  	dp := externalsecrets.DockerPullSecretType
   341  	res := createExternalSecretByType(projectID, namespace, &model.SecretManagerResponse{
   342  		Name:    "docker-pull",
   343  		Project: projectID,
   344  		Values: []*model.KeyValuesOutput{{
   345  			Key:   "dockerconfigjson",
   346  			Value: "config",
   347  		}},
   348  		Type: &dp,
   349  	})
   350  	sec, err := res.Build()
   351  	assert.NoError(t, err)
   352  	assert.Equal(t, "dockerconfigjson", sec.Spec.Data[0].SecretKey)
   353  }
   354  
   355  func generateSecrets(projectID string, secrets []string) []*model.SecretManagerResponse {
   356  	secretResp := make([]*model.SecretManagerResponse, 0)
   357  	for _, name := range secrets {
   358  		secretResp = append(secretResp, getSecretManagerResponse(name, projectID, "test_helmUrl", helmRepoSecretType))
   359  	}
   360  	dp := externalsecrets.DockerPullSecretType
   361  	secretResp = append(secretResp, &model.SecretManagerResponse{
   362  		Name:    "docker-pull",
   363  		Project: projectID,
   364  		Values: []*model.KeyValuesOutput{{
   365  			Key:   ".dockerconfigjson",
   366  			Value: "config",
   367  		}},
   368  		Type: &dp,
   369  	})
   370  	return secretResp
   371  }
   372  
   373  func TestHelmService_GetHelmCharts(t *testing.T) {
   374  	srv := createHelmRepoClient(t, map[string][]byte{})
   375  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   376  		assert.Equal(t, helmSecret, *name)
   377  		assert.Nil(t, owner)
   378  		assert.Equal(t, helmRepoSecretType, *_type)
   379  		assert.True(t, getValues)
   380  		assert.Equal(t, projectID, _projectID)
   381  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   382  	}
   383  
   384  	gcpService := createGCPServiceMock(t, getSecret)
   385  
   386  	service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil)
   387  
   388  	helmCharts, err := service.GetHelmCharts(context.Background(), helmSecret, projectID)
   389  	assert.NoError(t, err)
   390  	assert.Len(t, helmCharts, 2)
   391  	actual := funk.Find(helmCharts, func(chart *model.HelmChart) bool { return chart.Name == chartName }).(*model.HelmChart)
   392  	expected := getHelmManifestResponse(srv.URL).Entries[chartName][0]
   393  	assert.Equal(t, expected.Name, actual.Name)
   394  	assert.Equal(t, expected.Description, actual.Description)
   395  	assert.Equal(t, expected.Version, actual.Version)
   396  	assert.Equal(t, expected.AppVersion, actual.AppVersion)
   397  	assert.Equal(t, expected.Icon, actual.Icon)
   398  	assert.Equal(t, expected.Keywords, actual.Keywords)
   399  	assert.Equal(t, expected.Sources, actual.Sources)
   400  }
   401  
   402  func TestHelmService_GetHelmChartVersion(t *testing.T) {
   403  	srv := createHelmRepoClient(t, map[string][]byte{})
   404  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   405  		assert.Equal(t, helmSecret, *name)
   406  		assert.Nil(t, owner)
   407  		assert.Equal(t, helmRepoSecretType, *_type)
   408  		assert.True(t, getValues)
   409  		assert.Equal(t, projectID, _projectID)
   410  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   411  	}
   412  
   413  	gcpService := createGCPServiceMock(t, getSecret)
   414  
   415  	service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil)
   416  
   417  	helmVersions, err := service.GetHelmChartVersion(context.Background(), chartName, helmSecret, projectID)
   418  	assert.NoError(t, err)
   419  	assert.Len(t, helmVersions.Versions, 2)
   420  	versions := funk.Map(helmVersions.Versions, func(s *string) string { return *s }).([]string)
   421  	assert.Contains(t, []string{chartVersion, "1.1"}, versions[0])
   422  	assert.Contains(t, []string{chartVersion, "1.1"}, versions[1])
   423  }
   424  
   425  func TestHelmService_GetDefaultConfigSchema(t *testing.T) {
   426  	params := getHelmConfigSchemaParams()
   427  	configValueURL := fmt.Sprintf("/%s-%s/values.yaml", params.ChartName, params.ChartVersion)
   428  	schemaURL := fmt.Sprintf("/%s-%s/values.schema.json", params.ChartName, params.ChartVersion)
   429  	srv := createHelmRepoClient(t, map[string][]byte{configValueURL: []byte(configValue), schemaURL: []byte(configSchema)})
   430  
   431  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   432  		assert.Equal(t, helmSecret, *name)
   433  		assert.Nil(t, owner)
   434  		assert.Equal(t, helmRepoSecretType, *_type)
   435  		assert.True(t, getValues)
   436  		assert.Equal(t, projectID, _projectID)
   437  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   438  	}
   439  
   440  	gcpService := createGCPServiceMock(t, getSecret)
   441  
   442  	service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil)
   443  
   444  	helmConfig, err := service.GetDefaultConfigSchema(context.Background(), params.ChartName, params.SecretName, params.ChartVersion, projectID)
   445  
   446  	assert.NoError(t, err)
   447  	assert.NotNil(t, helmConfig)
   448  	assert.NotEmpty(t, helmConfig.ConfigVals)
   449  	assert.Equal(t, *helmConfig.ConfigVals, `# The pod name
   450  Name: my-alpine
   451  `)
   452  }
   453  
   454  func TestHelmService_GetHelmRepositoryInfo(t *testing.T) {
   455  	params := getHelmConfigSchemaParams()
   456  	url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion)
   457  	srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)})
   458  
   459  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   460  		assert.Equal(t, helmSecret, *name)
   461  		assert.Nil(t, owner)
   462  		assert.Equal(t, helmRepoSecretType, *_type)
   463  		assert.True(t, getValues)
   464  		assert.Equal(t, projectID, _projectID)
   465  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   466  	}
   467  
   468  	gcpService := createGCPServiceMock(t, getSecret)
   469  
   470  	service := NewHelmService(appConfig, nil, gcpService, nil, nil, nil)
   471  
   472  	repoInfo, err := service.GetHelmRepositoryInfo(context.Background(), params, projectID)
   473  
   474  	assert.NoError(t, err)
   475  	assert.NotNil(t, repoInfo)
   476  	assert.Nil(t, repoInfo.Metadata)
   477  	assert.NotEmpty(t, repoInfo.Readme)
   478  }
   479  func TestHelmService_GetHelmWorkloads(t *testing.T) {
   480  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   481  	helmEdgeID := "be8536ff-d463-4aff-8fa9-fe81fec1ddc1"
   482  	clusterEdgeID := testClusterEdgeID
   483  	bannerEdgeID := testBannerEdgeID
   484  
   485  	if err != nil {
   486  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   487  	}
   488  	defer db.Close()
   489  
   490  	params := getHelmConfigSchemaParams()
   491  	url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion)
   492  	srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)})
   493  
   494  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
   495  		assert.Equal(t, "test-helm-workload", *name)
   496  		assert.Nil(t, owner)
   497  		assert.Equal(t, helmRepoSecretType, *_type)
   498  		assert.True(t, getValues)
   499  		assert.Equal(t, projectID, _projectID)
   500  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
   501  	}
   502  
   503  	gcpService := createGCPServiceMock(t, getSecret)
   504  	secret := &model.HelmSecrets{
   505  		SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642",
   506  		Name:         "test-secret2",
   507  		CreatedAt:    "2022-10-19 17:33:07.347283+00",
   508  		UpdatedAt:    "2022-10-19 17:33:07.347283+00",
   509  	}
   510  
   511  	helmWorkload := getTestHelmWorkloadQuery()
   512  
   513  	service := NewHelmService(appConfig, nil, gcpService, db, nil, nil)
   514  
   515  	type test struct {
   516  		testName       string
   517  		clusterEdgeID  string
   518  		bannerEdgeID   string
   519  		expectedCount  int
   520  		mockSQLQueries []func() *sqlmock.ExpectedQuery
   521  	}
   522  	tests := []test{
   523  		{testName: "GetHelmWorkloadsByClusterEdgeID", clusterEdgeID: clusterEdgeID, bannerEdgeID: bannerEdgeID, expectedCount: 1,
   524  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
   525  				func() *sqlmock.ExpectedQuery {
   526  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID).
   527  						WithArgs(clusterEdgeID).
   528  						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"}).
   529  							AddRow(
   530  								clusterEdgeID,
   531  								bannerEdgeID,
   532  								helmWorkload.HelmEdgeID,
   533  								helmWorkload.Name,
   534  								helmWorkload.Namespace,
   535  								helmWorkload.HelmChart,
   536  								helmWorkload.HelmRepository,
   537  								helmWorkload.HelmChartVersion,
   538  								helmWorkload.HelmConfig,
   539  								helmWorkload.InstalledBy,
   540  								helmWorkload.WorkloadInstallationType,
   541  								helmWorkload.CreatedAt,
   542  								helmWorkload.UpdatedAt,
   543  								helmWorkload.HelmRepoSecret,
   544  								helmWorkload.ProjectID, false))
   545  				},
   546  				func() *sqlmock.ExpectedQuery {
   547  					return mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID).
   548  						WithArgs(helmEdgeID).
   549  						WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}).
   550  							AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt))
   551  				},
   552  				func() *sqlmock.ExpectedQuery {
   553  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
   554  						WithArgs(helmEdgeID).
   555  						WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}).
   556  							AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at"))
   557  				},
   558  				func() *sqlmock.ExpectedQuery {
   559  					return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID).
   560  						WithArgs(helmEdgeID).
   561  						WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
   562  							AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
   563  				},
   564  			},
   565  		},
   566  		{testName: "GetHelmWorkloadsByBannerEdgeID", clusterEdgeID: "", bannerEdgeID: bannerEdgeID, expectedCount: 1,
   567  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
   568  				func() *sqlmock.ExpectedQuery {
   569  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByBannerEdgeID).
   570  						WithArgs(bannerEdgeID).
   571  						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"}).
   572  							AddRow(
   573  								clusterEdgeID,
   574  								bannerEdgeID,
   575  								helmWorkload.HelmEdgeID,
   576  								helmWorkload.Name,
   577  								helmWorkload.Namespace,
   578  								helmWorkload.HelmChart,
   579  								helmWorkload.HelmRepository,
   580  								helmWorkload.HelmChartVersion,
   581  								helmWorkload.HelmConfig,
   582  								helmWorkload.InstalledBy,
   583  								helmWorkload.WorkloadInstallationType,
   584  								helmWorkload.CreatedAt,
   585  								helmWorkload.UpdatedAt,
   586  								helmWorkload.HelmRepoSecret,
   587  								helmWorkload.ProjectID, false))
   588  				},
   589  				func() *sqlmock.ExpectedQuery {
   590  					return mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID).
   591  						WithArgs(helmEdgeID).
   592  						WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}).
   593  							AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt))
   594  				},
   595  				func() *sqlmock.ExpectedQuery {
   596  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
   597  						WithArgs(helmEdgeID).
   598  						WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}).
   599  							AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at"))
   600  				},
   601  				func() *sqlmock.ExpectedQuery {
   602  					return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID).
   603  						WithArgs(helmEdgeID).
   604  						WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
   605  							AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
   606  				},
   607  			},
   608  		},
   609  	}
   610  
   611  	for _, tc := range tests {
   612  		for _, mockSQLFn := range tc.mockSQLQueries {
   613  			mockSQLFn()
   614  		}
   615  		t.Run(tc.testName, func(t *testing.T) {
   616  			var response []*model.HelmWorkload
   617  			var err error
   618  			if tc.testName == "GetHelmWorkloadsByClusterEdgeID" {
   619  				response, err = service.GetHelmWorkloads(context.Background(), &clusterEdgeID, &bannerEdgeID, true)
   620  			} else {
   621  				var emptyClusterEdgeID *string
   622  				response, err = service.GetHelmWorkloads(context.Background(), emptyClusterEdgeID, &bannerEdgeID, true)
   623  			}
   624  
   625  			responseMap := make(map[string]bool, 0)
   626  			for i := 0; i < len(response); i++ {
   627  				if responseMap[response[i].HelmEdgeID] == true {
   628  					assert.Fail(t, fmt.Sprintf("duplicate helm release returned: %s", response[i].Name))
   629  				} else {
   630  					responseMap[response[i].HelmEdgeID] = true
   631  				}
   632  			}
   633  			assert.NoError(t, err)
   634  			assert.Equal(t, len(response), tc.expectedCount)
   635  
   636  			assert.Equal(t, len(response[0].Configmaps), 1)
   637  			assert.Equal(t, response[0].Configmaps[0].ConfigMap, "config_map")
   638  		})
   639  	}
   640  
   641  	t.Run("GetHelmWorkloadsFailureScenario", func(t *testing.T) {
   642  		var emptyClusterEdgeID *string
   643  		var emptyBannerEdgeID *string
   644  		_, err := service.GetHelmWorkloads(context.Background(), emptyClusterEdgeID, emptyBannerEdgeID, true)
   645  		assert.EqualError(t, err, "please provide clusterEdgeId or bannerEdgeId")
   646  	})
   647  }
   648  
   649  func TestHelmService_GetAttachedHelmSecrets(t *testing.T) {
   650  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   651  	helmEdgeID := "be8536ff-d463-4aff-8fa9-fe81fec1ddc1"
   652  	if err != nil {
   653  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   654  	}
   655  	defer db.Close()
   656  	secret := &model.HelmSecrets{
   657  		SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642",
   658  		Name:         "test-secret2",
   659  		CreatedAt:    "2022-10-19 17:33:07.347283+00",
   660  		UpdatedAt:    "2022-10-19 17:33:07.347283+00",
   661  	}
   662  
   663  	mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID).
   664  		WithArgs("be8536ff-d463-4aff-8fa9-fe81fec1ddc1").
   665  		WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}).
   666  			AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt))
   667  	mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
   668  		WithArgs(helmEdgeID).
   669  		WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}).
   670  			AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at"))
   671  	mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID).
   672  		WithArgs(helmEdgeID).
   673  		WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
   674  			AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
   675  
   676  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
   677  	response, err := service.GetAttachedHelmSecrets(context.Background(), &helmEdgeID)
   678  	assert.NoError(t, err)
   679  	assert.Equal(t, len(response), 1)
   680  }
   681  
   682  func TestHelmService_GetHelmWorkloadsData(t *testing.T) {
   683  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   684  	clusterEdgeID := testClusterEdgeID
   685  	bannerEdgeID := testBannerEdgeID
   686  	if err != nil {
   687  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   688  	}
   689  	defer db.Close()
   690  
   691  	helmWorkload := getTestHelmWorkloadQuery()
   692  
   693  	mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID).
   694  		WithArgs(clusterEdgeID).
   695  		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"}).
   696  			AddRow(
   697  				clusterEdgeID,
   698  				bannerEdgeID,
   699  				helmWorkload.HelmEdgeID,
   700  				helmWorkload.Name,
   701  				helmWorkload.Namespace,
   702  				helmWorkload.HelmChart,
   703  				helmWorkload.HelmRepository,
   704  				helmWorkload.HelmChartVersion,
   705  				helmWorkload.HelmConfig,
   706  				helmWorkload.InstalledBy,
   707  				helmWorkload.WorkloadInstallationType,
   708  				helmWorkload.CreatedAt,
   709  				helmWorkload.UpdatedAt,
   710  				helmWorkload.HelmRepoSecret,
   711  				helmWorkload.ProjectID, false))
   712  
   713  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
   714  	response, err := service.GetHelmWorkloadsData(context.Background(), &clusterEdgeID, &bannerEdgeID, true)
   715  	assert.NoError(t, err)
   716  	assert.Equal(t, len(response), 1)
   717  }
   718  func TestHelmService_checkNamespaceToDelete(t *testing.T) {
   719  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   720  	clusterEdgeID := testClusterEdgeID
   721  	bannerEdgeID := testBannerEdgeID
   722  
   723  	if err != nil {
   724  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   725  	}
   726  	defer db.Close()
   727  
   728  	var helmWorkload = getTestHelmWorkloadQuery()
   729  
   730  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
   731  
   732  	type test struct {
   733  		testName      string
   734  		clusterEdgeID string
   735  		workloadName  string
   736  		want          bool
   737  		mockSQLQuery  func() *sqlmock.ExpectedQuery
   738  	}
   739  
   740  	tests := []test{
   741  		//case1: namespace used on only one workload, isDeleteNamespace should be true
   742  		{testName: "deleteNamespace", clusterEdgeID: clusterEdgeID, workloadName: helmWorkload.Name, want: true,
   743  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   744  				return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID).
   745  					WithArgs(clusterEdgeID).
   746  					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"}).
   747  						AddRow(
   748  							clusterEdgeID,
   749  							bannerEdgeID,
   750  							helmWorkload.HelmEdgeID,
   751  							helmWorkload.Name,
   752  							helmWorkload.Namespace,
   753  							helmWorkload.HelmChart,
   754  							helmWorkload.HelmRepository,
   755  							helmWorkload.HelmChartVersion,
   756  							helmWorkload.HelmConfig,
   757  							helmWorkload.InstalledBy,
   758  							helmWorkload.WorkloadInstallationType,
   759  							helmWorkload.CreatedAt,
   760  							helmWorkload.UpdatedAt,
   761  							helmWorkload.HelmRepoSecret,
   762  							helmWorkload.ProjectID, false))
   763  			},
   764  		},
   765  		//case2: namespace used on two workloads, isDeleteNamespace should be false
   766  		{testName: "notDeleteNamespace", clusterEdgeID: clusterEdgeID, workloadName: helmWorkload.Name, want: false,
   767  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   768  				return mock.ExpectQuery(sqlquery.GetHelmWorkloadsByClusterEdgeID).
   769  					WithArgs(clusterEdgeID).
   770  					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"}).
   771  						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).
   772  						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))
   773  			},
   774  		},
   775  	}
   776  
   777  	for i, tc := range tests {
   778  		tc.mockSQLQuery()
   779  		t.Run(tc.testName, func(t *testing.T) {
   780  			workload, isDeleteNamespace, err := service.checkNamespaceToDelete(context.Background(), &tests[i].clusterEdgeID, tc.workloadName)
   781  			assert.Equal(t, tc.workloadName, workload.Name)
   782  			assert.Equal(t, tc.want, isDeleteNamespace)
   783  			assert.NoError(t, err)
   784  		})
   785  	}
   786  }
   787  func TestHelmService_addSecretsToDeleteToChariotMessage(t *testing.T) {
   788  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   789  	clusterEdgeID := testClusterEdgeID
   790  	if err != nil {
   791  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   792  	}
   793  	defer db.Close()
   794  	defaultValue := ""
   795  
   796  	helmWorkload := &model.HelmWorkload{
   797  		HelmEdgeID:       "be8536ff-d463-4aff-8fa9-fe81fec1ddc1",
   798  		Name:             "test-helm-workload",
   799  		Namespace:        "nginx",
   800  		HelmChart:        "nginx",
   801  		HelmRepository:   "test-repo",
   802  		HelmChartVersion: "2.3.1",
   803  		ConfigValues:     &defaultValue,
   804  		InstalledBy:      &defaultValue,
   805  		HelmRepoSecret:   "test-helm-workload",
   806  	}
   807  
   808  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
   809  
   810  	type test struct {
   811  		testName      string
   812  		clusterEdgeID string
   813  		workload      *model.HelmWorkload
   814  		messageLength int
   815  		want          []string
   816  		mockSQLQuery  func() *sqlmock.ExpectedQuery
   817  	}
   818  
   819  	tests := []test{
   820  		//case1: one oecret
   821  		{testName: "oneSecret", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 2,
   822  			want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0IiwibmFtZXNwYWNlIjoibmdpbngiLCJjcmVhdGlvblRpbWVzdGFtcCI6bnVsbH0sInNwZWMiOnsic2VjcmV0U3RvcmVSZWYiOnsibmFtZSI6IiJ9LCJ0YXJnZXQiOnt9fSwic3RhdHVzIjp7InJlZnJlc2hUaW1lIjpudWxsLCJiaW5kaW5nIjp7fX19"},
   823  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   824  				return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID).
   825  					WithArgs(clusterEdgeID, helmWorkload.Namespace).
   826  					WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}).
   827  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret))
   828  			},
   829  		},
   830  		//case2: two secrets
   831  		{testName: "twoSecrets", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 3,
   832  			want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0IiwibmFtZXNwYWNlIjoibmdpbngiLCJjcmVhdGlvblRpbWVzdGFtcCI6bnVsbH0sInNwZWMiOnsic2VjcmV0U3RvcmVSZWYiOnsibmFtZSI6IiJ9LCJ0YXJnZXQiOnt9fSwic3RhdHVzIjp7InJlZnJlc2hUaW1lIjpudWxsLCJiaW5kaW5nIjp7fX19", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0MiIsIm5hbWVzcGFjZSI6Im5naW54IiwiY3JlYXRpb25UaW1lc3RhbXAiOm51bGx9LCJzcGVjIjp7InNlY3JldFN0b3JlUmVmIjp7Im5hbWUiOiIifSwidGFyZ2V0Ijp7fX0sInN0YXR1cyI6eyJyZWZyZXNoVGltZSI6bnVsbCwiYmluZGluZyI6e319fQ=="},
   833  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   834  				return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID).
   835  					WithArgs(clusterEdgeID, helmWorkload.Namespace).
   836  					WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}).
   837  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret).
   838  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2"))
   839  			},
   840  		},
   841  		//case3: one of two secrets use both use in another workload
   842  		{testName: "twoSecretsBothUsed1", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 2,
   843  			want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319", "eyJraW5kIjoiRXh0ZXJuYWxTZWNyZXQiLCJhcGlWZXJzaW9uIjoiZXh0ZXJuYWwtc2VjcmV0cy5pby92MWJldGExIiwibWV0YWRhdGEiOnsibmFtZSI6IkV4dGVybmFsU2VjcmV0MiIsIm5hbWVzcGFjZSI6Im5naW54IiwiY3JlYXRpb25UaW1lc3RhbXAiOm51bGx9LCJzcGVjIjp7InNlY3JldFN0b3JlUmVmIjp7Im5hbWUiOiIifSwidGFyZ2V0Ijp7fX0sInN0YXR1cyI6eyJyZWZyZXNoVGltZSI6bnVsbCwiYmluZGluZyI6e319fQ=="},
   844  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   845  				return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID).
   846  					WithArgs(clusterEdgeID, helmWorkload.Namespace).
   847  					WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}).
   848  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret).
   849  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2").
   850  						AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, externalSecret))
   851  			},
   852  		},
   853  		//case4: two secrets both use in another workload
   854  		{testName: "twoSecretsBothUsed2", clusterEdgeID: clusterEdgeID, workload: helmWorkload, messageLength: 1,
   855  			want: []string{"eyJraW5kIjoiSGVsbVJlbGVhc2UiLCJhcGlWZXJzaW9uIjoiaGVsbS50b29sa2l0LmZsdXhjZC5pby92MiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJuYW1lc3BhY2UiOiJmbHV4LXN5c3RlbSIsImNyZWF0aW9uVGltZXN0YW1wIjpudWxsLCJsYWJlbHMiOnsicGFyZW50LWNsdXN0ZXIiOiJyZWdpb24taW5mcmEiLCJzZWNyZXQtbWFtYWdlci5lZGdlLm5jci5jb20iOiIifX0sInNwZWMiOnsiY2hhcnQiOnsic3BlYyI6eyJjaGFydCI6IiIsInNvdXJjZVJlZiI6eyJraW5kIjoiSGVsbVJlcG9zaXRvcnkiLCJuYW1lIjoiIn19fSwiaW50ZXJ2YWwiOiIybTBzIiwicmVsZWFzZU5hbWUiOiJ0ZXN0LWhlbG0td29ya2xvYWQiLCJ0aW1lb3V0IjoiMTVtMHMiLCJkcmlmdERldGVjdGlvbiI6eyJtb2RlIjoiZW5hYmxlZCJ9LCJpbnN0YWxsIjp7InJlbWVkaWF0aW9uIjp7InJldHJpZXMiOjN9fSwidXBncmFkZSI6eyJyZW1lZGlhdGlvbiI6eyJyZXRyaWVzIjozfX0sInZhbHVlcyI6bnVsbCwicG9zdFJlbmRlcmVycyI6W3sia3VzdG9taXplIjp7InBhdGNoZXMiOlt7InBhdGNoIjoiLSBvcDogYWRkXG4gIHBhdGg6IC9tZXRhZGF0YS9hbm5vdGF0aW9ucy9oZWxtLnRvb2xraXQuZmx1eGNkLmlvfjFkcmlmdERldGVjdGlvblxuICB2YWx1ZTogZGlzYWJsZWQiLCJ0YXJnZXQiOnsidmVyc2lvbiI6InYxIiwia2luZCI6IklFTlBhdGNoIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL21ldGFkYXRhL2Fubm90YXRpb25zL2hlbG0udG9vbGtpdC5mbHV4Y2QuaW9+MWRyaWZ0RGV0ZWN0aW9uXG4gIHZhbHVlOiBkaXNhYmxlZCIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvbWV0YWRhdGEvYW5ub3RhdGlvbnMvaGVsbS50b29sa2l0LmZsdXhjZC5pb34xZHJpZnREZXRlY3Rpb25cbiAgdmFsdWU6IGRpc2FibGVkIiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEYWVtb25TZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJEZXBsb3ltZW50In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiU3RhdGVmdWxTZXQifX0seyJwYXRjaCI6Ii0gb3A6IGFkZFxuICBwYXRoOiAvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJSZXBsaWNhU2V0In19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZToge1wibm9kZUFmZmluaXR5XCI6IHtcInByZWZlcnJlZER1cmluZ1NjaGVkdWxpbmdJZ25vcmVkRHVyaW5nRXhlY3V0aW9uXCI6W3tcIndlaWdodFwiOjEsXCJwcmVmZXJlbmNlXCI6e1wibWF0Y2hFeHByZXNzaW9uc1wiOlt7XCJrZXlcIjpcIm5vZGUubmNyLmNvbS9jbGFzc1wiLFwib3BlcmF0b3JcIjpcIkluXCIsXCJ2YWx1ZXNcIjpbXCJzZXJ2ZXJcIl19XX19XX0gfSIsInRhcmdldCI6eyJ2ZXJzaW9uIjoidjEiLCJraW5kIjoiSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvam9iVGVtcGxhdGUvc3BlYy90ZW1wbGF0ZS9zcGVjL2FmZmluaXR5XG4gIHZhbHVlOiB7XCJub2RlQWZmaW5pdHlcIjoge1wicHJlZmVycmVkRHVyaW5nU2NoZWR1bGluZ0lnbm9yZWREdXJpbmdFeGVjdXRpb25cIjpbe1wid2VpZ2h0XCI6MSxcInByZWZlcmVuY2VcIjp7XCJtYXRjaEV4cHJlc3Npb25zXCI6W3tcImtleVwiOlwibm9kZS5uY3IuY29tL2NsYXNzXCIsXCJvcGVyYXRvclwiOlwiSW5cIixcInZhbHVlc1wiOltcInNlcnZlclwiXX1dfX1dfSB9IiwidGFyZ2V0Ijp7InZlcnNpb24iOiJ2MSIsImtpbmQiOiJDcm9uSm9iIn19LHsicGF0Y2giOiItIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvc3BlYy9hZmZpbml0eVxuICB2YWx1ZTpcbiAgICBub2RlQWZmaW5pdHk6XG4gICAgICBwcmVmZXJyZWREdXJpbmdTY2hlZHVsaW5nSWdub3JlZER1cmluZ0V4ZWN1dGlvbjpcbiAgICAgIC0gcHJlZmVyZW5jZTpcbiAgICAgICAgICBtYXRjaEV4cHJlc3Npb25zOlxuICAgICAgICAgIC0ga2V5OiBub2RlLm5jci5jb20vY2xhc3NcbiAgICAgICAgICAgIG9wZXJhdG9yOiBJblxuICAgICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgLSBzZXJ2ZXJcbiAgICAgICAgd2VpZ2h0OiAxXG4tIG9wOiBhZGRcbiAgcGF0aDogL3NwZWMvdGVtcGxhdGUvbWV0YWRhdGEvYW5ub3RhdGlvbnMvZWRnZS5uY3IuY29tfjFoZWxtLWVkZ2UtaWRcbiAgdmFsdWU6IFwiXCJcbiIsInRhcmdldCI6eyJncm91cCI6Imt1YmV2aXJ0LmlvIiwidmVyc2lvbiI6InYxIiwia2luZCI6IlZpcnR1YWxNYWNoaW5lIn19XX19XX0sInN0YXR1cyI6e319"},
   856  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   857  				return mock.ExpectQuery(sqlquery.GetNamespacesAndSecretsNamesByClusterEdgeID).
   858  					WithArgs(clusterEdgeID, helmWorkload.Namespace).
   859  					WillReturnRows(sqlmock.NewRows([]string{"helm_workloads.helm_edge_id", "helm_workloads.workload_name", "helm_workloads.workload_namespace", "helm_secrets.secret_name"}).
   860  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, externalSecret).
   861  						AddRow(helmWorkload.HelmEdgeID, helmWorkload.Name, helmWorkload.Namespace, "ExternalSecret2").
   862  						AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, externalSecret).
   863  						AddRow("be8536ff-d463-4aff-8fa9-fe81fec1ddc2", "workload2", helmWorkload.Namespace, "ExternalSecret2"))
   864  			},
   865  		},
   866  	}
   867  
   868  	for _, tc := range tests {
   869  		tc.mockSQLQuery()
   870  		t.Run(tc.testName, func(t *testing.T) {
   871  			var message []string
   872  			installationType := model.WorkloadInstallationTypeServerPreferred
   873  			helmRelease, err := mapper.ToCreateHelmReleaseBase64String(helmWorkload.Name, "", "", "", "", "", []byte{}, installationType, nil, "latest", "")
   874  			assert.NoError(t, err)
   875  			message = append(message, helmRelease)
   876  			message, err = service.addSecretsToDeleteToChariotMessage(context.Background(), helmWorkload, clusterEdgeID, message)
   877  			assert.Equal(t, tc.want, message)
   878  			assert.Equal(t, len(message), tc.messageLength)
   879  			assert.NoError(t, err)
   880  		})
   881  	}
   882  }
   883  
   884  // Unit test for parseRepoURLYaml
   885  
   886  func TestParseRepoURLYaml(t *testing.T) {
   887  	jsn := getHelmManifestResponse("ip")
   888  	response, _ := yaml.Marshal(&jsn)
   889  	_, err := parseRepoURLYaml(response)
   890  	if err != nil {
   891  		t.Fatalf(`Got error %v`, err)
   892  	}
   893  }
   894  
   895  func TestGetWorkloadsByName(t *testing.T) {
   896  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   897  	if err != nil {
   898  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   899  	}
   900  	defer db.Close()
   901  	service := NewHelmService(nil, nil, nil, db, nil, nil)
   902  
   903  	var (
   904  		helmEdgeID    = helmEdgeID
   905  		clusterEdgeID = testClusterEdgeID
   906  		workloadName  = "test-workload-name"
   907  	)
   908  	testCases := []struct {
   909  		title         string
   910  		helmEdgeID    *string
   911  		workloadName  string
   912  		clusterEdgeID string
   913  		mockSQLQuery  func() *sqlmock.ExpectedQuery
   914  	}{
   915  		{
   916  			title:         "GetHelmWorkloadsByNameAndID",
   917  			workloadName:  workloadName,
   918  			clusterEdgeID: clusterEdgeID,
   919  			// mockSQLQuery: func() *sqlmock.ExpectedExec {
   920  			// 	return mock.ExpectQuery(sqlquery.GetWorkloadsByNameAndID).
   921  			// 		WithArgs(helmEdgeID).
   922  			// 		WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "", ""}).
   923  			// 			AddRow(workloadName, helmEdgeID, clusterEdgeID))
   924  			// },
   925  			mockSQLQuery: func() *sqlmock.ExpectedQuery {
   926  				return mock.ExpectQuery(sqlquery.GetWorkloadsByNameAndID).
   927  					WithArgs(clusterEdgeID, workloadName).
   928  					WillReturnRows(sqlmock.NewRows([]string{"workload_name", "helm_edge_id", "cluster_edge_id"}).
   929  						AddRow(workloadName, helmEdgeID, clusterEdgeID))
   930  			},
   931  		},
   932  	}
   933  
   934  	for _, tc := range testCases {
   935  		tc.mockSQLQuery()
   936  
   937  		t.Run(tc.title, func(t *testing.T) {
   938  			helmWorkloads, err := service.GetHelmWorkloadsByName(context.Background(), tc.clusterEdgeID, tc.workloadName)
   939  			assert.NoError(t, err)
   940  			assert.NotEmpty(t, helmWorkloads)
   941  		})
   942  	}
   943  }
   944  
   945  func TestSoftDeleteHelmReleaseSQLEntry(t *testing.T) {
   946  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
   947  	if err != nil {
   948  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   949  	}
   950  	defer db.Close()
   951  	service := NewHelmService(nil, nil, nil, db, nil, nil)
   952  
   953  	var (
   954  		helmEdgeID    = helmEdgeID
   955  		clusterEdgeID = testClusterEdgeID
   956  		//workloadName  = "test-workload-name"
   957  	)
   958  	testCases := []struct {
   959  		title          string
   960  		helmEdgeID     *string
   961  		workloadName   *string
   962  		clusterEdgeID  *string
   963  		mockSQLQueries []func() *sqlmock.ExpectedQuery
   964  		mockSQLExec    func() *sqlmock.ExpectedExec
   965  		expectErr      bool
   966  	}{
   967  		{
   968  			title:         "Pass in helmEdgeID only",
   969  			helmEdgeID:    &helmEdgeID,
   970  			workloadName:  nil,
   971  			clusterEdgeID: nil,
   972  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
   973  				func() *sqlmock.ExpectedQuery {
   974  					return mock.ExpectQuery(sqlquery.GetClusterEdgeIDsUsingHelmWorkloadLabels).
   975  						WithArgs(helmEdgeID).
   976  						WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id"}).
   977  							AddRow(clusterEdgeID))
   978  				},
   979  			},
   980  			mockSQLExec: func() *sqlmock.ExpectedExec {
   981  				return mock.ExpectExec(sqlquery.DeleteHelmWorkload).WithArgs(helmEdgeID).
   982  					WillReturnResult(sqlmock.NewResult(1, 1))
   983  			},
   984  			expectErr: true,
   985  		},
   986  		{
   987  			title:         "Pass in nil only",
   988  			helmEdgeID:    nil,
   989  			workloadName:  nil,
   990  			clusterEdgeID: nil,
   991  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
   992  				func() *sqlmock.ExpectedQuery {
   993  					return nil
   994  				},
   995  			},
   996  			mockSQLExec: func() *sqlmock.ExpectedExec {
   997  				return nil
   998  			},
   999  			expectErr: true,
  1000  		},
  1001  	}
  1002  
  1003  	for _, tc := range testCases {
  1004  		for _, mockSQLFn := range tc.mockSQLQueries {
  1005  			mockSQLFn()
  1006  		}
  1007  
  1008  		tc.mockSQLExec()
  1009  
  1010  		t.Run(tc.title, func(t *testing.T) {
  1011  			err := service.SoftDeleteHelmReleaseSQL(context.Background(), tc.helmEdgeID, tc.workloadName, tc.clusterEdgeID)
  1012  			if tc.expectErr {
  1013  				assert.Error(t, err)
  1014  			} else {
  1015  				assert.NoError(t, err)
  1016  			}
  1017  		})
  1018  	}
  1019  }
  1020  
  1021  func TestUpdateHelmReleaseSQLEntry(t *testing.T) {
  1022  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1023  	if err != nil {
  1024  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1025  	}
  1026  	defer db.Close()
  1027  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1028  
  1029  	username := "test-user"
  1030  	version := "1.2.2"
  1031  	configValues := "configValues"
  1032  	helmEdgeID := "aa46d745-adf3-4482-955d-c046178a67ea"
  1033  	namespace := "test-ns"
  1034  	now := time.Now()
  1035  	ctx := middleware.NewContext(context.Background(), &types.AuthUser{
  1036  		Username: "test-user",
  1037  	})
  1038  
  1039  	type testCase struct {
  1040  		title          string
  1041  		version        *string
  1042  		configValues   *string
  1043  		configMaps     []model.InjectableConfigmaps
  1044  		mockSQLQueries func() []interface{}
  1045  	}
  1046  	testCases := []testCase{
  1047  		{
  1048  			title:        "Version and config values are provided, no config map(s) selected",
  1049  			version:      &version,
  1050  			configValues: &configValues,
  1051  			configMaps:   nil,
  1052  			mockSQLQueries: func() []interface{} {
  1053  				return []interface{}{
  1054  					mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)),
  1055  					mock.ExpectExec(sqlquery.DeleteHelmConfigmaps).WithArgs(helmEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)),
  1056  				}
  1057  			},
  1058  		},
  1059  		{
  1060  			title:        "Version and config values are not provided, no config map(s) selected",
  1061  			version:      nil,
  1062  			configValues: nil,
  1063  			configMaps:   nil,
  1064  			mockSQLQueries: func() []interface{} {
  1065  				return []interface{}{
  1066  					mock.ExpectQuery(sqlquery.GetHelmWorkloadInfoByHelmEdgeID).WithArgs(helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"helm_chart_version", "helm_config"}).AddRow(version, configValues)),
  1067  					mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)),
  1068  					mock.ExpectExec(sqlquery.DeleteHelmConfigmaps).WithArgs(helmEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)),
  1069  				}
  1070  			},
  1071  		},
  1072  		{
  1073  			title:        "Version and config values are provided, EdgeInfo and BSLInfo config maps selected",
  1074  			version:      &version,
  1075  			configValues: &configValues,
  1076  			configMaps:   []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo, model.InjectableConfigmapsBSLInfo},
  1077  			mockSQLQueries: func() []interface{} {
  1078  				return []interface{}{
  1079  					mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)),
  1080  					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"})),
  1081  					mock.ExpectBegin(),
  1082  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsEdgeInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1083  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsBSLInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1084  					mock.ExpectCommit(),
  1085  				}
  1086  			},
  1087  		},
  1088  		{
  1089  			title:        "Version and config values are provided, EdgeInfo config map selected and BSLInfo config map deselected",
  1090  			version:      &version,
  1091  			configValues: &configValues,
  1092  			configMaps:   []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo},
  1093  			mockSQLQueries: func() []interface{} {
  1094  				return []interface{}{
  1095  					mock.ExpectQuery(sqlquery.UpdateHelmWorkload).WithArgs(version, configValues, username, helmEdgeID).WillReturnRows(sqlmock.NewRows([]string{"workload_namespace"}).AddRow(namespace)),
  1096  					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"}).
  1097  						AddRow("test-edge-id", helmEdgeID, namespace, model.InjectableConfigmapsBSLInfo.String(), now, now)),
  1098  					mock.ExpectBegin(),
  1099  					mock.ExpectExec(sqlquery.DeleteHelmConfigmap).WithArgs(helmEdgeID, model.InjectableConfigmapsBSLInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1100  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, namespace, model.InjectableConfigmapsEdgeInfo.String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1101  					mock.ExpectCommit(),
  1102  				}
  1103  			},
  1104  		},
  1105  	}
  1106  
  1107  	for _, tc := range testCases {
  1108  		tc.mockSQLQueries()
  1109  
  1110  		t.Run(tc.title, func(t *testing.T) {
  1111  			err := service.UpdateHelmReleaseSQL(ctx, helmEdgeID, tc.version, tc.configValues, tc.configMaps)
  1112  			assert.NoError(t, err)
  1113  			assert.NoError(t, mock.ExpectationsWereMet())
  1114  		})
  1115  	}
  1116  }
  1117  
  1118  func TestCreateHelmReleaseSQLEntry(t *testing.T) {
  1119  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1120  	if err != nil {
  1121  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1122  	}
  1123  	defer db.Close()
  1124  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1125  
  1126  	// When the installtion type is not defined in the payload, this should be the default installation type
  1127  	defaultInstallationType := model.WorkloadInstallationTypeServerPreferred
  1128  	name := "hr-name"
  1129  	configValues := "configValues"
  1130  	secrets := []string{"secret1", "secret2"}
  1131  	cluster := getTestCluster("test-cluster")
  1132  	hrPayload := getHelmPayload(&cluster.BannerEdgeID, &cluster.ClusterEdgeID, name, configValues, secrets...)
  1133  	hrPayloadNoBanner := getHelmPayload(nil, &cluster.ClusterEdgeID, name, configValues, secrets...)
  1134  	hrPayloadNoCluster := getHelmPayload(&cluster.BannerEdgeID, nil, name, configValues, secrets...)
  1135  	hrPayloadNoIDs := getHelmPayload(nil, nil, name, configValues, secrets...)
  1136  	ctx := middleware.NewContext(context.Background(), &types.AuthUser{
  1137  		Username: "test-user",
  1138  	})
  1139  
  1140  	type testCase struct {
  1141  		title          string
  1142  		expectErr      bool
  1143  		payload        model.HelmReleasePayload
  1144  		cluster        *model.Cluster
  1145  		mockSQLQueries func() []interface{}
  1146  	}
  1147  	testCases := []testCase{
  1148  		{
  1149  			title:     "HelmReleasePayload has both bannerEdgeID and clusterEdgeID",
  1150  			expectErr: false,
  1151  			payload:   hrPayload,
  1152  			cluster:   cluster,
  1153  			mockSQLQueries: func() []interface{} {
  1154  				return []interface{}{
  1155  					mock.ExpectBegin(),
  1156  					mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(*hrPayload.BannerEdgeID, hrPayload.Name, hrPayload.Namespace, hrPayload.HelmChart, hrPayload.HelmRepository, hrPayload.Version, *hrPayload.ConfigValues, "test-user", defaultInstallationType, hrPayload.Secret).
  1157  						WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)),
  1158  					mock.ExpectExec(sqlquery.CreateWorkloadClusterMapper).WithArgs(helmEdgeID, *hrPayload.ClusterEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)),
  1159  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)),
  1160  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)),
  1161  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayload.Namespace, hrPayload.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1162  					mock.ExpectCommit(),
  1163  				}
  1164  			},
  1165  		},
  1166  		{
  1167  			// If the payload does not have a clusterEdgeID, the cluster model will also be nil
  1168  			title:     "HelmReleasePayload only has bannerEdgeID",
  1169  			expectErr: false,
  1170  			payload:   hrPayloadNoCluster,
  1171  			cluster:   nil,
  1172  			mockSQLQueries: func() []interface{} {
  1173  				return []interface{}{
  1174  					mock.ExpectBegin(),
  1175  					mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(*hrPayloadNoCluster.BannerEdgeID, hrPayloadNoCluster.Name, hrPayloadNoCluster.Namespace, hrPayloadNoCluster.HelmChart, hrPayloadNoCluster.HelmRepository, hrPayloadNoCluster.Version, *hrPayloadNoCluster.ConfigValues, "test-user", defaultInstallationType, hrPayloadNoCluster.Secret).
  1176  						WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)),
  1177  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)),
  1178  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)),
  1179  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayloadNoCluster.Namespace, hrPayloadNoCluster.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1180  					mock.ExpectCommit(),
  1181  				}
  1182  			},
  1183  		},
  1184  		{
  1185  			title:     "HelmReleasePayload only has clusterEdgeID",
  1186  			expectErr: false,
  1187  			payload:   hrPayloadNoBanner,
  1188  			cluster:   cluster,
  1189  			mockSQLQueries: func() []interface{} {
  1190  				return []interface{}{
  1191  					mock.ExpectBegin(),
  1192  					mock.ExpectQuery(sqlquery.CreateHelmWorkload).WithArgs(cluster.BannerEdgeID, hrPayloadNoBanner.Name, hrPayloadNoBanner.Namespace, hrPayloadNoBanner.HelmChart, hrPayloadNoBanner.HelmRepository, hrPayloadNoBanner.Version, *hrPayloadNoBanner.ConfigValues, "test-user", defaultInstallationType, hrPayloadNoBanner.Secret).
  1193  						WillReturnRows(mock.NewRows([]string{"helm_edge_id"}).AddRow(helmEdgeID)),
  1194  					mock.ExpectExec(sqlquery.CreateWorkloadClusterMapper).WithArgs(helmEdgeID, *hrPayloadNoBanner.ClusterEdgeID).WillReturnResult(sqlmock.NewResult(1, 1)),
  1195  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret1").WillReturnResult(sqlmock.NewResult(1, 1)),
  1196  					mock.ExpectExec(sqlquery.CreateHelmSecret).WithArgs(helmEdgeID, "secret2").WillReturnResult(sqlmock.NewResult(1, 1)),
  1197  					mock.ExpectExec(sqlquery.CreateHelmConfigmaps).WithArgs(helmEdgeID, hrPayloadNoBanner.Namespace, hrPayloadNoBanner.InjectConfigmaps[0].String()).WillReturnResult(sqlmock.NewResult(1, 1)),
  1198  					mock.ExpectCommit(),
  1199  				}
  1200  			},
  1201  		},
  1202  		{
  1203  			title:     "HelmReleasePayload does not have bannerEdgeID nor clusterEdgeID",
  1204  			expectErr: true,
  1205  			payload:   hrPayloadNoIDs,
  1206  			cluster:   nil,
  1207  			mockSQLQueries: func() []interface{} {
  1208  				return nil
  1209  			},
  1210  		},
  1211  	}
  1212  
  1213  	for _, tc := range testCases {
  1214  		tc.mockSQLQueries()
  1215  
  1216  		t.Run(tc.title, func(t *testing.T) {
  1217  			err := service.CreateHelmReleaseSQL(ctx, tc.payload, tc.cluster)
  1218  			if tc.expectErr {
  1219  				assert.Error(t, err)
  1220  			} else {
  1221  				assert.NoError(t, err)
  1222  				assert.NoError(t, mock.ExpectationsWereMet())
  1223  			}
  1224  		})
  1225  	}
  1226  }
  1227  
  1228  func TestHelmService_GetHelmWorkload(t *testing.T) {
  1229  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1230  
  1231  	if err != nil {
  1232  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1233  	}
  1234  	defer db.Close()
  1235  
  1236  	params := getHelmConfigSchemaParams()
  1237  	url := fmt.Sprintf("/%s-%s/README.md", params.ChartName, params.ChartVersion)
  1238  	srv := createHelmRepoClient(t, map[string][]byte{url: []byte(readme)})
  1239  
  1240  	getSecret := func(_ context.Context, name *string, owner, _type *string, getValues bool, _projectID string) ([]*model.SecretManagerResponse, error) {
  1241  		assert.Equal(t, "test-helm-workload", *name)
  1242  		assert.Nil(t, owner)
  1243  		assert.Equal(t, helmRepoSecretType, *_type)
  1244  		assert.True(t, getValues)
  1245  		assert.Equal(t, projectID, _projectID)
  1246  		return []*model.SecretManagerResponse{getSecretManagerResponse(*name, _projectID, srv.URL, helmRepoSecretType)}, nil
  1247  	}
  1248  
  1249  	gcpService := createGCPServiceMock(t, getSecret)
  1250  	secret := &model.HelmSecrets{
  1251  		SecretEdgeID: "af7351a3-22e0-4b76-aeeb-2f9d77a2b642",
  1252  		Name:         "test-secret2",
  1253  		CreatedAt:    "2022-10-19 17:33:07.347283+00",
  1254  		UpdatedAt:    "2022-10-19 17:33:07.347283+00",
  1255  	}
  1256  	defaultValue := ""
  1257  	deleted := false
  1258  
  1259  	helmWorkload := helmTypes.HelmWorkloadQuery{
  1260  		ClusterEdgeID:            testClusterEdgeID,
  1261  		BannerEdgeID:             testBannerEdgeID,
  1262  		HelmEdgeID:               helmEdgeID,
  1263  		Name:                     "test-helm-workload",
  1264  		Namespace:                "nginx",
  1265  		HelmChart:                "nginx",
  1266  		HelmRepository:           "test-repo",
  1267  		HelmChartVersion:         "2.3.1",
  1268  		HelmConfig:               &defaultValue,
  1269  		InstalledBy:              &defaultValue,
  1270  		WorkloadInstallationType: "mockInstallationType",
  1271  		CreatedAt:                "mockCreatedAt",
  1272  		UpdatedAt:                "mockUpdatedAt",
  1273  		HelmRepoSecret:           "test-helm-workload",
  1274  		ProjectID:                "test-org",
  1275  		Deleted:                  &deleted,
  1276  	}
  1277  	service := NewHelmService(appConfig, nil, gcpService, db, nil, nil)
  1278  
  1279  	mock.ExpectQuery(sqlquery.GetHelmWorkload).
  1280  		WithArgs(helmEdgeID, testClusterEdgeID).
  1281  		WillReturnRows(sqlmock.NewRows([]string{"clusters.cluster_edge_id", "helm_workloads.banner_edge_id", "helm_workloads.helm_edge_id",
  1282  			"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"}).
  1283  			AddRow(
  1284  				helmWorkload.ClusterEdgeID,
  1285  				helmWorkload.BannerEdgeID,
  1286  				helmWorkload.HelmEdgeID,
  1287  				helmWorkload.Name,
  1288  				helmWorkload.Namespace,
  1289  				helmWorkload.HelmChart,
  1290  				helmWorkload.HelmRepository,
  1291  				helmWorkload.HelmChartVersion,
  1292  				helmWorkload.HelmConfig,
  1293  				helmWorkload.InstalledBy,
  1294  				helmWorkload.WorkloadInstallationType,
  1295  				helmWorkload.CreatedAt,
  1296  				helmWorkload.UpdatedAt,
  1297  				helmWorkload.HelmRepoSecret,
  1298  				helmWorkload.ProjectID,
  1299  				helmWorkload.Deleted))
  1300  
  1301  	mock.ExpectQuery(sqlquery.GetAttachedHelmSecretByHelmEdgeID).
  1302  		WithArgs(helmWorkload.HelmEdgeID).
  1303  		WillReturnRows(sqlmock.NewRows([]string{"secret_edge_id", "secret_name", "created_at", "updated_at"}).
  1304  			AddRow(secret.SecretEdgeID, secret.Name, secret.CreatedAt, secret.UpdatedAt))
  1305  
  1306  	mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
  1307  		WithArgs(helmWorkload.HelmEdgeID).
  1308  		WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}).
  1309  			AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at"))
  1310  
  1311  	mock.ExpectQuery(sqlquery.SelectEdgeLabelsForHelmEdgeID).
  1312  		WithArgs(helmWorkload.HelmEdgeID).
  1313  		WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
  1314  			AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
  1315  
  1316  	response, err := service.GetHelmWorkload(context.Background(), helmEdgeID, testClusterEdgeID)
  1317  	assert.NoError(t, err)
  1318  	assert.NoError(t, mock.ExpectationsWereMet())
  1319  	assert.Equal(t, "test-helm-workload", response.Name)
  1320  }
  1321  
  1322  func TestHelmService_GetHelmWorkloadConfigmaps(t *testing.T) {
  1323  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1324  	clusterEdgeID := testClusterEdgeID
  1325  	testHelmEdgeID := helmEdgeID
  1326  
  1327  	if err != nil {
  1328  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1329  	}
  1330  	defer db.Close()
  1331  
  1332  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
  1333  
  1334  	type test struct {
  1335  		testName       string
  1336  		clusterEdgeID  *string
  1337  		helmEdgeID     string
  1338  		expectedCount  int
  1339  		mockSQLQueries []func() *sqlmock.ExpectedQuery
  1340  	}
  1341  
  1342  	tests := []test{
  1343  		{testName: "GetHelmworkloadConfigMapCountOne",
  1344  			clusterEdgeID: &clusterEdgeID,
  1345  			helmEdgeID:    testHelmEdgeID,
  1346  			expectedCount: 1,
  1347  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
  1348  				func() *sqlmock.ExpectedQuery {
  1349  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
  1350  						WithArgs(helmEdgeID).
  1351  						WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}).
  1352  							AddRow("helm_workload_configmap_edge_id", helmEdgeID, "namespace", "config_map", "created_at", "updated_at"))
  1353  				},
  1354  			},
  1355  		},
  1356  		{testName: "GetHelmworkloadConfigMapCountZero",
  1357  			clusterEdgeID: &clusterEdgeID,
  1358  			helmEdgeID:    testHelmEdgeID,
  1359  			expectedCount: 0,
  1360  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{ //nolint
  1361  				func() *sqlmock.ExpectedQuery {
  1362  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadConfigmaps).
  1363  						WithArgs(helmEdgeID).
  1364  						WillReturnRows(sqlmock.NewRows([]string{"helm_workload_configmap_edge_id", "helm_edge_id", "namespace", "config_map", "created_at", "updated_at"}))
  1365  				},
  1366  			},
  1367  		},
  1368  	}
  1369  
  1370  	for _, tc := range tests {
  1371  		for _, mockSQLFn := range tc.mockSQLQueries {
  1372  			mockSQLFn()
  1373  		}
  1374  
  1375  		t.Run(tc.testName, func(t *testing.T) {
  1376  			response, err := service.GetHelmWorkloadConfigmaps(context.Background(), tc.helmEdgeID)
  1377  			assert.NoError(t, err)
  1378  			assert.Equal(t, tc.expectedCount, len(response))
  1379  
  1380  			if tc.expectedCount == 0 {
  1381  				emptyConfigMapList := make([]*model.HelmWorkloadConfigmaps, 0)
  1382  				assert.Equal(t, emptyConfigMapList, response)
  1383  			}
  1384  		})
  1385  	}
  1386  }
  1387  
  1388  func TestHelmService_DeleteHelmWorkloadSecrets(t *testing.T) {
  1389  	testSecretNames := []string{"test-secret-02"}
  1390  	testHelmID := helmEdgeID
  1391  
  1392  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1393  	if err != nil {
  1394  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1395  	}
  1396  	defer db.Close()
  1397  
  1398  	mock.ExpectExec(sqlquery.DeleteHelmSecret).WithArgs(testHelmID, testSecretNames[0]).
  1399  		WillReturnResult(sqlmock.NewResult(1, 1))
  1400  
  1401  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
  1402  
  1403  	if _, err = service.DeleteHelmSecrets(context.Background(), testHelmID, testSecretNames); err != nil {
  1404  		t.Errorf("error deleting secrets: %s", err)
  1405  	}
  1406  	assert.NoError(t, err)
  1407  	if err := mock.ExpectationsWereMet(); err != nil {
  1408  		t.Errorf("there were unfulfilled expectations: %s", err)
  1409  	}
  1410  }
  1411  
  1412  func TestHelmService_GetHelmStatus(t *testing.T) {
  1413  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1414  	if err != nil {
  1415  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1416  	}
  1417  	defer db.Close()
  1418  
  1419  	ctx := middleware.NewContext(context.Background(), &types.AuthUser{
  1420  		Username: "test-user",
  1421  	})
  1422  	workloadName := "test-helm-release"
  1423  	workloadNamespace := "test-helm-release-ns"
  1424  	helmChartName := "test-chart"
  1425  	helmRepoName := "test-repository"
  1426  	testCluster := "test-cluster-123"
  1427  	updatedTime, _ := time.Parse(time.RFC3339, "2024-01-01T01:00:00.000000-00:00")
  1428  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1429  
  1430  	type test struct {
  1431  		testName       string
  1432  		clusterEdgeID  string
  1433  		createdAt      string
  1434  		updatedAt      string
  1435  		expected       *model.HelmStatus
  1436  		mockSQLQueries []func() *sqlmock.ExpectedQuery
  1437  	}
  1438  	tests := []test{{
  1439  		testName:      "successful-helm-release",
  1440  		clusterEdgeID: testCluster,
  1441  		createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1442  		updatedAt:     "2024-01-01T01:00:00.000000-00:00",
  1443  		expected: &model.HelmStatus{
  1444  			Status:  status.Ready,
  1445  			Message: status.WorkloadReadyStatusMessage,
  1446  			Pods: []*model.Pods{
  1447  				{Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"},
  1448  				{Name: "test-helm-pod2", Status: status.Running, Message: "Pod is ready"},
  1449  			},
  1450  		},
  1451  		mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1452  			func() *sqlmock.ExpectedQuery {
  1453  				return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1454  					WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1455  						AddRow("test-helm-pod1", "\"True\"", "false").
  1456  						AddRow("test-helm-pod2", "\"True\"", "false"))
  1457  			},
  1458  			func() *sqlmock.ExpectedQuery {
  1459  				return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1460  					WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1461  						AddRow("test-helm-pod1", "", "true").
  1462  						AddRow("test-helm-pod2", "", "true"))
  1463  			},
  1464  			func() *sqlmock.ExpectedQuery {
  1465  				return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1466  					WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime))
  1467  			},
  1468  			func() *sqlmock.ExpectedQuery {
  1469  				return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster).
  1470  					WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"True\"", "false"))
  1471  			},
  1472  			func() *sqlmock.ExpectedQuery {
  1473  				return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRelease", workloadName, testCluster).
  1474  					WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"UpgradeSucceeded\"", "false"))
  1475  			},
  1476  		},
  1477  	},
  1478  		{
  1479  			testName:      "failed-helm-release",
  1480  			clusterEdgeID: testCluster,
  1481  			createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1482  			updatedAt:     "2024-01-01T01:00:00.000000-00:00",
  1483  			expected: &model.HelmStatus{
  1484  				Status:  status.Error,
  1485  				Message: "HelmRelease: UpgradeFailed, helmChart: Failed to get Helm Chart, helmRepo: Failed to get Helm Repo",
  1486  				Pods: []*model.Pods{
  1487  					{Name: "test-helm-pod1", Status: status.Error, Message: "Pod Failed"},
  1488  				},
  1489  			},
  1490  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1491  				func() *sqlmock.ExpectedQuery {
  1492  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1493  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1494  							AddRow("test-helm-pod1", "\"False\"", "false"))
  1495  				},
  1496  				func() *sqlmock.ExpectedQuery {
  1497  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1498  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1499  							AddRow("test-helm-pod1", "Pod Failed", "false"))
  1500  				},
  1501  				func() *sqlmock.ExpectedQuery {
  1502  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1503  						WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime))
  1504  				},
  1505  				func() *sqlmock.ExpectedQuery {
  1506  					return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster).
  1507  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false"))
  1508  				},
  1509  				func() *sqlmock.ExpectedQuery {
  1510  					return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRelease", workloadName, testCluster).
  1511  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"UpgradeFailed\"", "false"))
  1512  				},
  1513  				func() *sqlmock.ExpectedQuery {
  1514  					return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmChart", helmChartName, testCluster).
  1515  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false"))
  1516  				},
  1517  				func() *sqlmock.ExpectedQuery {
  1518  					return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmChart", helmChartName, testCluster).
  1519  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"Failed to get Helm Chart\"", "false"))
  1520  				},
  1521  				func() *sqlmock.ExpectedQuery {
  1522  					return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRepo", helmRepoName, testCluster).
  1523  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"False\"", "false"))
  1524  				},
  1525  				func() *sqlmock.ExpectedQuery {
  1526  					return mock.ExpectQuery(sqlquery.GetHelmConditionReason).WithArgs("HelmRepo", helmRepoName, testCluster).
  1527  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"Failed to get Helm Repo\"", "false"))
  1528  				},
  1529  			},
  1530  		},
  1531  		{
  1532  			testName:      "installing-helm-release",
  1533  			clusterEdgeID: testCluster,
  1534  			createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1535  			updatedAt:     "2024-01-01T01:00:00.000000-00:00",
  1536  			expected: &model.HelmStatus{
  1537  				Status:  status.Installing,
  1538  				Message: status.InstallingStatusMessage,
  1539  				Pods:    []*model.Pods{},
  1540  			},
  1541  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1542  				func() *sqlmock.ExpectedQuery {
  1543  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1544  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}))
  1545  				},
  1546  				func() *sqlmock.ExpectedQuery {
  1547  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1548  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}))
  1549  				},
  1550  				func() *sqlmock.ExpectedQuery {
  1551  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1552  						WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime))
  1553  				},
  1554  				func() *sqlmock.ExpectedQuery {
  1555  					return mock.ExpectQuery(sqlquery.GetHelmConditionStatus).WithArgs("HelmRelease", workloadName, testCluster).
  1556  						WillReturnRows(mock.NewRows([]string{"watched_field_values.value", "watched_field_values.missing"}).AddRow("\"\"", "true"))
  1557  				},
  1558  			},
  1559  		},
  1560  		{
  1561  			testName:      "installing-helm-release-no-watched-entry",
  1562  			clusterEdgeID: testCluster,
  1563  			createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1564  			updatedAt:     "2024-01-01T01:00:00.000000-00:00",
  1565  			expected: &model.HelmStatus{
  1566  				Status:  status.Installing,
  1567  				Message: status.InstallingStatusMessage,
  1568  				Pods:    []*model.Pods{},
  1569  			},
  1570  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1571  				func() *sqlmock.ExpectedQuery {
  1572  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1573  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}))
  1574  				},
  1575  				func() *sqlmock.ExpectedQuery {
  1576  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1577  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}))
  1578  				},
  1579  				func() *sqlmock.ExpectedQuery {
  1580  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1581  						WillReturnRows(mock.NewRows([]string{"watched_at"}))
  1582  				},
  1583  			},
  1584  		},
  1585  		{
  1586  			testName:      "updating-helm-release",
  1587  			clusterEdgeID: testCluster,
  1588  			createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1589  			updatedAt:     "2024-01-02T01:00:00.000000-00:00",
  1590  			expected: &model.HelmStatus{
  1591  				Status:  status.Updating,
  1592  				Message: status.UpdatingStatusMessage,
  1593  				Pods: []*model.Pods{
  1594  					{Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"},
  1595  					{Name: "test-helm-pod2", Status: status.Error, Message: "Pod Failed"},
  1596  				},
  1597  			},
  1598  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1599  				func() *sqlmock.ExpectedQuery {
  1600  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1601  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1602  							AddRow("test-helm-pod1", "\"True\"", "false").
  1603  							AddRow("test-helm-pod2", "\"False\"", "false"))
  1604  				},
  1605  				func() *sqlmock.ExpectedQuery {
  1606  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1607  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1608  							AddRow("test-helm-pod1", "", "true").
  1609  							AddRow("test-helm-pod2", "Pod Failed", "false"))
  1610  				},
  1611  				func() *sqlmock.ExpectedQuery {
  1612  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1613  						WillReturnRows(mock.NewRows([]string{"watched_at"}).AddRow(updatedTime))
  1614  				},
  1615  			},
  1616  		},
  1617  		{
  1618  			testName:      "updating-helm-release-no-watched-entry",
  1619  			clusterEdgeID: testCluster,
  1620  			createdAt:     "2024-01-01T01:00:00.000000-00:00",
  1621  			updatedAt:     "2024-01-02T01:00:00.000000-00:00",
  1622  			expected: &model.HelmStatus{
  1623  				Status:  status.Updating,
  1624  				Message: status.UpdatingStatusMessage,
  1625  				Pods: []*model.Pods{
  1626  					{Name: "test-helm-pod1", Status: status.Running, Message: "Pod is ready"},
  1627  					{Name: "test-helm-pod2", Status: status.Running, Message: "Pod is ready"},
  1628  				},
  1629  			},
  1630  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1631  				func() *sqlmock.ExpectedQuery {
  1632  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsStatus).WithArgs(testCluster, workloadNamespace).
  1633  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1634  							AddRow("test-helm-pod1", "\"True\"", "false").
  1635  							AddRow("test-helm-pod2", "\"True\"", "false"))
  1636  				},
  1637  				func() *sqlmock.ExpectedQuery {
  1638  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadPodsReason).WithArgs(testCluster, workloadNamespace).
  1639  						WillReturnRows(mock.NewRows([]string{"watched_field_objects.name", "watched_field_values.value", "watched_field_values.missing"}).
  1640  							AddRow("test-helm-pod1", "", "true").
  1641  							AddRow("test-helm-pod2", "", "true"))
  1642  				},
  1643  				func() *sqlmock.ExpectedQuery {
  1644  					return mock.ExpectQuery(sqlquery.GetHelmWorkloadWatchedTime).WithArgs(workloadName, testCluster).
  1645  						WillReturnRows(mock.NewRows([]string{"watched_at"}))
  1646  				},
  1647  			},
  1648  		},
  1649  	}
  1650  
  1651  	for _, tc := range tests {
  1652  		for _, mockSQLFn := range tc.mockSQLQueries {
  1653  			mockSQLFn()
  1654  		}
  1655  
  1656  		t.Run(tc.testName, func(t *testing.T) {
  1657  			combinedStatus, err := service.GetHelmStatus(ctx, testCluster, workloadName, workloadNamespace, helmChartName, helmRepoName, tc.createdAt, tc.updatedAt, &falseValue)
  1658  			assert.NoError(t, err)
  1659  			assert.Equal(t, tc.expected.Status, combinedStatus.Status)
  1660  			assert.Equal(t, tc.expected.Message, combinedStatus.Message)
  1661  			assert.Equal(t, len(tc.expected.Pods), len(combinedStatus.Pods))
  1662  			for _, pod1 := range tc.expected.Pods {
  1663  				for _, pod2 := range combinedStatus.Pods {
  1664  					if pod1.Name == pod2.Name {
  1665  						assert.Equal(t, pod1.Status, pod2.Status)
  1666  						assert.Equal(t, pod1.Message, pod2.Message)
  1667  					}
  1668  				}
  1669  			}
  1670  		})
  1671  	}
  1672  }
  1673  
  1674  func TestHelmService_GetHelmStatusWithoutClusterID(t *testing.T) {
  1675  	db, _, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1676  	if err != nil {
  1677  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1678  	}
  1679  	defer db.Close()
  1680  
  1681  	ctx := middleware.NewContext(context.Background(), &types.AuthUser{
  1682  		Username: "test-user",
  1683  	})
  1684  	workloadName := "test-helm-release"
  1685  	workloadNamespace := "test-helm-release-ns"
  1686  	helmChartName := "test-chart"
  1687  	helmRepoName := "test-repository"
  1688  	//testCluster := "test-cluster-123"
  1689  	includeDeleted := false
  1690  
  1691  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1692  
  1693  	type test struct {
  1694  		testName       string
  1695  		clusterEdgeID  string
  1696  		createdAt      string
  1697  		updatedAt      string
  1698  		deleted        *bool
  1699  		expected       *model.HelmStatus
  1700  		mockSQLQueries []func() *sqlmock.ExpectedQuery
  1701  	}
  1702  	tests := []test{
  1703  		{
  1704  			testName:      "passing-in-empty-clusterEdgeID",
  1705  			clusterEdgeID: "",
  1706  			deleted:       &includeDeleted,
  1707  			expected: &model.HelmStatus{
  1708  				Status:  status.NotAvailable,
  1709  				Message: status.NotDeployedStatusMessage,
  1710  			},
  1711  			mockSQLQueries: []func() *sqlmock.ExpectedQuery{
  1712  				func() *sqlmock.ExpectedQuery {
  1713  					return nil
  1714  				},
  1715  			},
  1716  		},
  1717  	}
  1718  
  1719  	for _, tc := range tests {
  1720  		for _, mockSQLFn := range tc.mockSQLQueries {
  1721  			mockSQLFn()
  1722  		}
  1723  
  1724  		t.Run(tc.testName, func(t *testing.T) {
  1725  			combinedStatus, err := service.GetHelmStatus(ctx, tc.clusterEdgeID, workloadName, workloadNamespace, helmChartName, helmRepoName, tc.createdAt, tc.updatedAt, tc.deleted)
  1726  
  1727  			assert.NoError(t, err)
  1728  			assert.Equal(t, tc.expected.Status, combinedStatus.Status)
  1729  			assert.Equal(t, tc.expected.Message, combinedStatus.Message)
  1730  			assert.Empty(t, combinedStatus.Pods)
  1731  		})
  1732  	}
  1733  }
  1734  
  1735  func TestDeleteLabelFromHelmWorkload(t *testing.T) {
  1736  	testHelmID := "test-helm-delete"
  1737  	testLabelID := "test-label-id-delete"
  1738  
  1739  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1740  	if err != nil {
  1741  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1742  	}
  1743  	defer db.Close()
  1744  
  1745  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1746  	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]")
  1747  	errMsg := sqlerr.Wrap(errMock)
  1748  
  1749  	type result struct {
  1750  		result bool
  1751  		err    error
  1752  	}
  1753  
  1754  	type test struct {
  1755  		testName       string
  1756  		expected       result
  1757  		testLabel      string
  1758  		mockSQLQueries []func() *sqlmock.ExpectedExec
  1759  	}
  1760  
  1761  	tests := []test{ //nolint
  1762  		{
  1763  			testName: "Delete single valid label",
  1764  			expected: result{
  1765  				result: true,
  1766  				err:    nil,
  1767  			},
  1768  			testLabel: testLabelID,
  1769  			mockSQLQueries: []func() *sqlmock.ExpectedExec{
  1770  				func() *sqlmock.ExpectedExec {
  1771  					testRes := mock.ExpectExec(sqlquery.DeleteLabelFromHelmWorkload).WithArgs(testLabelID, testHelmID).
  1772  						WillReturnResult(sqlmock.NewResult(1, 1))
  1773  					return testRes
  1774  				},
  1775  			},
  1776  		},
  1777  		{
  1778  			testName: "Delete single invalid label",
  1779  			expected: result{
  1780  				result: false,
  1781  				err:    errMsg,
  1782  			},
  1783  			testLabel: "jibberish",
  1784  			mockSQLQueries: []func() *sqlmock.ExpectedExec{
  1785  				func() *sqlmock.ExpectedExec {
  1786  					testRes := mock.ExpectExec(sqlquery.DeleteLabelFromHelmWorkload).WithArgs("dsadadasdasdsa", testHelmID).
  1787  						WillReturnResult(sqlmock.NewResult(1, 1))
  1788  					return testRes
  1789  				},
  1790  			},
  1791  		},
  1792  	}
  1793  	for _, tc := range tests {
  1794  		for _, mockSQLFn := range tc.mockSQLQueries {
  1795  			mockSQLFn()
  1796  		}
  1797  		t.Run(tc.testName, func(t *testing.T) {
  1798  			res, err := service.DeleteWorkloadLabel(context.Background(), testHelmID, tc.testLabel)
  1799  			if err != nil {
  1800  				assert.Error(t, err)
  1801  			}
  1802  			assert.Equal(t, tc.expected.result, res)
  1803  			assert.Equal(t, tc.expected.err, err)
  1804  		})
  1805  	}
  1806  }
  1807  
  1808  func TestAddLabelToHelmWorkload(t *testing.T) {
  1809  	testLabelIDForAdd := "test-label-id-add"
  1810  	helmWorkload := getTestHelmWorkloadQuery()
  1811  
  1812  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1813  	if err != nil {
  1814  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1815  	}
  1816  	defer db.Close()
  1817  
  1818  	service := NewHelmService(nil, nil, nil, db, nil, nil)
  1819  
  1820  	type result struct {
  1821  		result bool
  1822  		err    error
  1823  	}
  1824  
  1825  	type testAddWorkloadLabel struct {
  1826  		testName       string
  1827  		expected       result
  1828  		testLabel      string
  1829  		mockSQLQueries []func() *sqlmock.ExpectedExec
  1830  	}
  1831  	errMsg := fmt.Errorf("[{\"message\":\"Invalid input syntax for type\",\"extensions\":{\"additional\":{\"errorType\":\"EDGE_SQL_STATE\",\"severity\":\"\",\"statusCode\":\"Unknown\"},\"operationID\":\"\",\"version\":\"0.20.0\"}}]")
  1832  	sqlErr := sqlerr.Wrap(errMsg)
  1833  
  1834  	testAdd := []testAddWorkloadLabel{ //nolint
  1835  		{
  1836  			testName: "Add valid label",
  1837  			expected: result{
  1838  				result: true,
  1839  				err:    nil,
  1840  			},
  1841  			testLabel: testLabelIDForAdd,
  1842  			mockSQLQueries: []func() *sqlmock.ExpectedExec{
  1843  				func() *sqlmock.ExpectedExec {
  1844  					testRes := mock.ExpectExec(sqlquery.CreateHelmWorkloadLabels).WithArgs(helmWorkload.HelmEdgeID, testLabelIDForAdd).
  1845  						WillReturnResult(sqlmock.NewResult(1, 1))
  1846  					return testRes
  1847  				},
  1848  			},
  1849  		},
  1850  		{
  1851  			testName: "Add invalid label",
  1852  			expected: result{
  1853  				result: false,
  1854  				err:    sqlErr,
  1855  			},
  1856  			testLabel: "",
  1857  			mockSQLQueries: []func() *sqlmock.ExpectedExec{
  1858  				func() *sqlmock.ExpectedExec {
  1859  					testRes := mock.ExpectExec(sqlquery.CreateHelmWorkloadLabels).WithArgs(helmWorkload.HelmEdgeID, "").
  1860  						WillReturnError(errMsg)
  1861  					return testRes
  1862  				},
  1863  			},
  1864  		},
  1865  	}
  1866  	for _, tc := range testAdd {
  1867  		for _, mockSQLFn := range tc.mockSQLQueries {
  1868  			mockSQLFn()
  1869  		}
  1870  		t.Run(tc.testName, func(t *testing.T) {
  1871  			res, err := service.AddWorkloadLabel(context.Background(), helmWorkload.HelmEdgeID, tc.testLabel)
  1872  			if err != nil {
  1873  				assert.Error(t, err)
  1874  			}
  1875  			assert.Equal(t, tc.expected.result, res)
  1876  			assert.Equal(t, tc.expected.err, err)
  1877  		})
  1878  	}
  1879  }
  1880  
  1881  func GetBannerByHelmEdgeID(t *testing.T) {
  1882  	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  1883  	if err != nil {
  1884  		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
  1885  	}
  1886  	defer db.Close()
  1887  
  1888  	expectedProjectID := projectID
  1889  	mock.ExpectQuery(sqlquery.GetBannerByHelmEdgeID).WithArgs(helmEdgeID).
  1890  		WillReturnRows(mock.NewRows([]string{"project_id", "banner_edge_id"}).
  1891  			AddRow(expectedProjectID, bannerEdgeID))
  1892  
  1893  	service := NewHelmService(appConfig, nil, nil, db, nil, nil)
  1894  	banner, err := service.GetBannerByHelmEdgeID(context.Background(), helmEdgeID)
  1895  	assert.NoError(t, err)
  1896  	assert.Equal(t, expectedProjectID, banner.ProjectID)
  1897  	assert.Equal(t, bannerEdgeID, banner.BannerEdgeID)
  1898  
  1899  	if err := mock.ExpectationsWereMet(); err != nil {
  1900  		t.Errorf("there were unfulfilled expectations: %s", err)
  1901  	}
  1902  }
  1903  
  1904  func getTestHelmReleaseWithStatus(name string, succeededStatus bool) *helmApi.HelmRelease {
  1905  	helmRelease := &helmApi.HelmRelease{
  1906  		TypeMeta: metav1.TypeMeta{
  1907  			APIVersion: helmApi.GroupVersion.String(),
  1908  			Kind:       helmRelease,
  1909  		},
  1910  		ObjectMeta: metav1.ObjectMeta{
  1911  			Name:      name,
  1912  			Namespace: ns,
  1913  			Labels: map[string]string{
  1914  				mapper.SecretManagerSecretLabel: helmSecret,
  1915  			},
  1916  		},
  1917  		Spec: helmApi.HelmReleaseSpec{
  1918  			Interval: metav1.Duration{
  1919  				Duration: time.Duration(2) * time.Minute,
  1920  			},
  1921  			ReleaseName:     name,
  1922  			TargetNamespace: ns,
  1923  			Chart: &helmApi.HelmChartTemplate{
  1924  				Spec: helmApi.HelmChartTemplateSpec{
  1925  					Chart:   chartName,
  1926  					Version: chartVersion,
  1927  					SourceRef: helmApi.CrossNamespaceObjectReference{
  1928  						Kind: helmRepoKind,
  1929  						Name: name,
  1930  					},
  1931  				},
  1932  			},
  1933  			Values: &apiextensionsv1.JSON{
  1934  				Raw: []byte(configValue),
  1935  			},
  1936  			Timeout: &metav1.Duration{
  1937  				Duration: time.Duration(15) * time.Minute,
  1938  			},
  1939  		},
  1940  		Status: helmApi.HelmReleaseStatus{
  1941  			ObservedGeneration: 0,
  1942  			History: helmApi.Snapshots{
  1943  				&helmApi.Snapshot{
  1944  					ChartVersion: chartVersion,
  1945  				},
  1946  			},
  1947  		},
  1948  	}
  1949  	if succeededStatus {
  1950  		condition := metav1.Condition{
  1951  			Type:               "Ready",
  1952  			Status:             "True",
  1953  			LastTransitionTime: metav1.Now(),
  1954  			Reason:             "test reason",
  1955  			Message:            "reconciliation successful",
  1956  		}
  1957  		helmRelease.Status.Conditions = append(helmRelease.Status.Conditions, condition)
  1958  	} else {
  1959  		condition := metav1.Condition{
  1960  			Type:               helmApi.ReleasedCondition,
  1961  			Status:             "False",
  1962  			LastTransitionTime: metav1.Now(),
  1963  			Reason:             "test failure",
  1964  			Message:            "install failed",
  1965  		}
  1966  		helmRelease.Status.Conditions = append(helmRelease.Status.Conditions, condition)
  1967  	}
  1968  	return helmRelease
  1969  }
  1970  
  1971  func getTestHelmRepository(name string) *helmRepositoryApi.HelmRepository {
  1972  	return &helmRepositoryApi.HelmRepository{
  1973  		TypeMeta: metav1.TypeMeta{
  1974  			APIVersion: helmRepositoryApi.GroupVersion.String(),
  1975  			Kind:       helmRepoKind,
  1976  		},
  1977  		ObjectMeta: metav1.ObjectMeta{
  1978  			Name:              name,
  1979  			Namespace:         ns,
  1980  			CreationTimestamp: metav1.Now(),
  1981  		},
  1982  		Spec: helmRepositoryApi.HelmRepositorySpec{
  1983  			URL:       helmRepoURL,
  1984  			SecretRef: &meta.LocalObjectReference{Name: helmSecret},
  1985  			Interval:  metav1.Duration{Duration: 2 * time.Minute},
  1986  		},
  1987  	}
  1988  }
  1989  
  1990  func createHelmRepoClient(t *testing.T, mapping map[string][]byte) *httptest.Server {
  1991  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1992  		assert.Equal(t, http.MethodGet, r.Method)
  1993  		mapping["/index.yaml"] = getHelmCharts(t, r.Host)
  1994  		mapping[".tgz"] = []byte(zippedChart)
  1995  		for url, response := range mapping {
  1996  			if strings.HasSuffix(r.URL.String(), url) {
  1997  				w.WriteHeader(200)
  1998  				_, err := w.Write(response)
  1999  				assert.NoError(t, err)
  2000  				return
  2001  			}
  2002  		}
  2003  	}))
  2004  }
  2005  
  2006  func getHelmPayload(bannerEdgeID, clusterEdgeID *string, name, configValues string, secrets ...string) model.HelmReleasePayload {
  2007  	return model.HelmReleasePayload{
  2008  		Name:             name,
  2009  		Secret:           helmSecret,
  2010  		HelmRepository:   testHelmRepo,
  2011  		HelmChart:        chartName,
  2012  		Version:          chartVersion,
  2013  		BannerEdgeID:     bannerEdgeID,
  2014  		ClusterEdgeID:    clusterEdgeID,
  2015  		ConfigValues:     &configValues,
  2016  		Namespace:        ns,
  2017  		Secrets:          secrets,
  2018  		InjectConfigmaps: []model.InjectableConfigmaps{model.InjectableConfigmapsEdgeInfo},
  2019  	}
  2020  }
  2021  
  2022  func getTestCluster(name string) *model.Cluster {
  2023  	return &model.Cluster{
  2024  		ProjectID:     projectID,
  2025  		Name:          name,
  2026  		ClusterEdgeID: clusterEdgeID,
  2027  		BannerEdgeID:  bannerEdgeID,
  2028  	}
  2029  }
  2030  
  2031  func getSecretManagerResponse(name, project, URL, secretType string) *model.SecretManagerResponse { //nolint
  2032  
  2033  	var testKeyValues = []*model.KeyValuesOutput{
  2034  		{
  2035  			Key:   constants.HelmUsername,
  2036  			Value: "test_username",
  2037  		},
  2038  		{
  2039  			Key:   constants.HelmPassword,
  2040  			Value: "test_password",
  2041  		},
  2042  		{
  2043  			Key:   constants.HelmURL,
  2044  			Value: URL,
  2045  		},
  2046  		{
  2047  			Key:   constants.HelmRepoName,
  2048  			Value: name,
  2049  		},
  2050  	}
  2051  	return &model.SecretManagerResponse{
  2052  		Name:    name,
  2053  		Project: project,
  2054  		Values:  testKeyValues,
  2055  		Type:    &secretType,
  2056  	}
  2057  }
  2058  
  2059  func getHelmCharts(t *testing.T, url string) []byte {
  2060  	hmr := getHelmManifestResponse(url)
  2061  	res, err := yaml.Marshal(&hmr)
  2062  	assert.NoError(t, err)
  2063  	return res
  2064  }
  2065  
  2066  func getHelmManifestResponse(host string) repo.IndexFile {
  2067  	return repo.IndexFile{
  2068  		APIVersion: "v1",
  2069  		Entries: map[string]repo.ChartVersions{
  2070  			chartName: {
  2071  				{
  2072  					Metadata: &chart.Metadata{
  2073  
  2074  						Description: "test description 1",
  2075  						Name:        chartName,
  2076  						Version:     chartVersion,
  2077  						AppVersion:  "v1",
  2078  						Icon:        "icon",
  2079  						Home:        "home",
  2080  						Sources:     []string{"source1", "source2"},
  2081  						Keywords:    []string{"key1", "key2"},
  2082  					},
  2083  					URLs: []string{"http://" + host + "/charts.tgz", "http://" + host + "/charts.tgz"},
  2084  					//Created: time.Now(),
  2085  				},
  2086  				{Metadata: &chart.Metadata{Description: "test description 2", Name: "test name 2", Version: "1.1"}},
  2087  			},
  2088  			"helm_chart2": {
  2089  				{Metadata: &chart.Metadata{Description: "test description 3", Name: "test name 3", Version: "2.0.0"}},
  2090  			},
  2091  		},
  2092  	}
  2093  }
  2094  
  2095  func getHelmConfigSchemaParams() model.HelmConfigSchemaParams {
  2096  	return model.HelmConfigSchemaParams{
  2097  		SecretName:   helmSecret,
  2098  		BannerEdgeID: bannerEdgeID,
  2099  		ChartName:    chartName,
  2100  		ChartVersion: chartVersion,
  2101  	}
  2102  }
  2103  
  2104  type GetSecretsFunc = func(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error)
  2105  type GetKubeResourceFunc = func(ctx context.Context, projectID string, cluster *model.Cluster, input model.LoqRequest) ([]string, error)
  2106  
  2107  func createGCPServiceMock(t *testing.T, getSecret GetSecretsFunc) *mocks.MockGCPService {
  2108  	mock := gomock.NewController(t)
  2109  	service := mocks.NewMockGCPService(mock)
  2110  
  2111  	service.EXPECT().
  2112  		GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
  2113  		DoAndReturn(getSecret).AnyTimes()
  2114  	return service
  2115  }
  2116  
  2117  func createMockBQClient(t *testing.T, getKubeResource GetKubeResourceFunc) *mocks.MockBQClient {
  2118  	mock := gomock.NewController(t)
  2119  	service := mocks.NewMockBQClient(mock)
  2120  
  2121  	service.EXPECT().
  2122  		GetKubeResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
  2123  		DoAndReturn(getKubeResource).AnyTimes()
  2124  	return service
  2125  }
  2126  
  2127  func createChariotV2TestTopic(done chan bool, assertSubscriptionMessage func(message *pubSub.Message)) (option.ClientOption, error) {
  2128  	chariotPubsubClient, err := chariotClientApiTestutils.NewMockPubsubServer()
  2129  	if err != nil {
  2130  		return nil, err
  2131  	}
  2132  	_, err = chariotClientApiTestutils.CreateMockTopic(context.Background(), projectID, testChariotPubsubTopic, chariotPubsubClient)
  2133  	if err != nil {
  2134  		return nil, err
  2135  	}
  2136  
  2137  	go func() {
  2138  		err := chariotClientApiTestutils.CreateMockSubscription(context.Background(), done, projectID, testChariotPubsubTopic, testChariotPubsubSubscription, 20*time.Second, "", assertSubscriptionMessage, chariotPubsubClient)
  2139  		if err != nil {
  2140  			fmt.Println(err)
  2141  		}
  2142  	}()
  2143  	return chariotPubsubClient, nil
  2144  }
  2145  
  2146  func getTestHelmWorkloadQuery() helmTypes.HelmWorkloadQuery {
  2147  	defaultValue := ""
  2148  
  2149  	return helmTypes.HelmWorkloadQuery{
  2150  		ClusterEdgeID:            testClusterEdgeID,
  2151  		BannerEdgeID:             testBannerEdgeID,
  2152  		HelmEdgeID:               "be8536ff-d463-4aff-8fa9-fe81fec1ddc1",
  2153  		Name:                     "test-helm-workload",
  2154  		Namespace:                "nginx",
  2155  		HelmChart:                "nginx",
  2156  		HelmRepository:           "test-repo",
  2157  		HelmChartVersion:         "2.3.1",
  2158  		HelmConfig:               &defaultValue,
  2159  		InstalledBy:              &defaultValue,
  2160  		WorkloadInstallationType: "mockInstallationType",
  2161  		CreatedAt:                "mockCreatedAt",
  2162  		UpdatedAt:                "mockUpdatedAt",
  2163  		HelmRepoSecret:           "test-helm-workload",
  2164  		ProjectID:                "test-org",
  2165  	}
  2166  }
  2167  

View as plain text