...

Source file src/edge-infra.dev/pkg/edge/api/graph/integration/unit_test.go

Documentation: edge-infra.dev/pkg/edge/api/graph/integration

     1  package integration_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"time"
    10  
    11  	pubSub "cloud.google.com/go/pubsub"
    12  	"cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
    13  	"github.com/99designs/gqlgen/client"
    14  	"github.com/99designs/gqlgen/graphql"
    15  	"github.com/99designs/gqlgen/graphql/handler"
    16  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/k8s/v1alpha1"
    17  	resourceApi "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/resourcemanager/v1beta1"
    18  	helmApi "github.com/fluxcd/helm-controller/api/v2"
    19  	"github.com/gin-gonic/gin"
    20  	"github.com/golang/mock/gomock"
    21  	"github.com/google/go-containerregistry/pkg/name"
    22  	_ "github.com/lib/pq"
    23  	"google.golang.org/api/compute/v1"
    24  	"google.golang.org/api/container/v1"
    25  	"google.golang.org/api/option"
    26  	corev1 "k8s.io/api/core/v1"
    27  	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    30  	"k8s.io/apimachinery/pkg/labels"
    31  	"k8s.io/apimachinery/pkg/runtime/schema"
    32  	"k8s.io/apimachinery/pkg/selection"
    33  	"k8s.io/apimachinery/pkg/util/wait"
    34  	"k8s.io/client-go/kubernetes/scheme"
    35  	"k8s.io/client-go/rest"
    36  	runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
    37  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    38  
    39  	"edge-infra.dev/pkg/edge/api/apierror"
    40  	bsltypes "edge-infra.dev/pkg/edge/api/bsl/types"
    41  	"edge-infra.dev/pkg/edge/api/clients"
    42  	"edge-infra.dev/pkg/edge/api/graph/generated"
    43  	"edge-infra.dev/pkg/edge/api/graph/mapper"
    44  	"edge-infra.dev/pkg/edge/api/graph/model"
    45  	"edge-infra.dev/pkg/edge/api/graph/resolver"
    46  	testApi "edge-infra.dev/pkg/edge/api/graph/test"
    47  	"edge-infra.dev/pkg/edge/api/middleware"
    48  	"edge-infra.dev/pkg/edge/api/mocks"
    49  	"edge-infra.dev/pkg/edge/api/services"
    50  	"edge-infra.dev/pkg/edge/api/services/artifacts"
    51  	clustersvc "edge-infra.dev/pkg/edge/api/services/cluster"
    52  	"edge-infra.dev/pkg/edge/api/services/clustersecrets"
    53  	"edge-infra.dev/pkg/edge/api/services/edgenode"
    54  	"edge-infra.dev/pkg/edge/api/services/kinform"
    55  	"edge-infra.dev/pkg/edge/api/services/virtualmachine"
    56  	edgesql "edge-infra.dev/pkg/edge/api/sql"
    57  	"edge-infra.dev/pkg/edge/api/testutils"
    58  	"edge-infra.dev/pkg/edge/api/testutils/seededpostgres"
    59  	"edge-infra.dev/pkg/edge/api/types"
    60  	"edge-infra.dev/pkg/edge/api/utils"
    61  	"edge-infra.dev/pkg/edge/bsl"
    62  	chariotAPI "edge-infra.dev/pkg/edge/chariot/client"
    63  	"edge-infra.dev/pkg/edge/constants/api/fleet"
    64  	"edge-infra.dev/pkg/edge/ctlfish"
    65  	"edge-infra.dev/pkg/edge/ctlfish/monitor"
    66  	edgeAgentClientApi "edge-infra.dev/pkg/edge/edgeagent/model"
    67  	"edge-infra.dev/pkg/edge/info"
    68  	"edge-infra.dev/pkg/edge/okta"
    69  	"edge-infra.dev/pkg/f8n/warehouse/pallet"
    70  	unstructuredutil "edge-infra.dev/pkg/k8s/unstructured"
    71  	fftest "edge-infra.dev/pkg/lib/featureflag/testutil"
    72  	iamutils "edge-infra.dev/pkg/lib/gcp/iam/utils"
    73  	"edge-infra.dev/pkg/lib/runtime/version"
    74  	"edge-infra.dev/test/fixtures"
    75  	"edge-infra.dev/test/framework"
    76  	chariotClientApiTestutils "edge-infra.dev/test/framework/gcp/pubsub"
    77  )
    78  
    79  const (
    80  	topLevelProjectID             = "topLevelProjectId"
    81  	testProject                   = "test-org"
    82  	testServiceAccountEmail       = "test-app@appspot.gserviceaccount.com"
    83  	testOauth2ClientID            = "test-oauth-2-client-id"
    84  	testChariotPubsubTopic        = "chariot-pubsub-topic"
    85  	testChariotPubsubSubscription = "chariot-pubsub-subscription"
    86  	testClusterEdgeID             = "3396a52c-6a22-4049-9593-5a63b596a200"
    87  	testClusterEdgeID2            = "3396a52c-6a22-4049-9593-5a63b596a201"
    88  	testResetURL                  = "https://www.example.com"
    89  )
    90  
    91  var (
    92  	ClusterDeletedCount = 0
    93  	testOrgBannerEdgeID = "3396a52c-6a22-4049-9593-5a63b596a101"
    94  
    95  	MockCtrl       *gomock.Controller
    96  	runtimeClient  runtimeclient.Client
    97  	seededPostgres *seededpostgres.SeededPostgres
    98  
    99  	defaultCfg = &types.Config{}
   100  )
   101  
   102  func cleanupUnitTest() {
   103  	if seededPostgres != nil {
   104  		err := seededPostgres.Close()
   105  		if err != nil {
   106  			panic(err)
   107  		}
   108  	}
   109  }
   110  
   111  func setupUnitTest(config *types.TestConfig) (*Suite, error) {
   112  	runtimeClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).Build() // used only for unit tests
   113  	// default retry for unit test
   114  	defaultRetry = wait.Backoff{
   115  		Steps:    2,
   116  		Duration: 2 * time.Second,
   117  		Factor:   1.1, // change here for backoff
   118  		Jitter:   0.1,
   119  	}
   120  
   121  	chariotClient, err := createChariotV2TestTopic()
   122  	if err != nil {
   123  		panic(err)
   124  	}
   125  
   126  	// mock feature flags
   127  	fftest.MustInitTestFeatureFlags(map[string]bool{})
   128  
   129  	bspMockServer := services.GetMockBspServer(testOrg, testApi.TestOrgID, testUser, testUserRole, testEmail, testResetURL)
   130  	mockGkeClient := createGKEMockClient()
   131  	mockContainer := mockeGKEContainer()
   132  	mockCompute := createMockComputeService()
   133  	mockSecretManager := createMockForSecretManager()
   134  	mockBigQuery := createMockBigQuery()
   135  	mockCompatibility := createMockCompatibilityService()
   136  
   137  	mockGCP := mocks.NewMockGcpClientService(MockCtrl)
   138  	mockGCP.EXPECT().GetSecretClient(gomock.Any(), gomock.Any()).Return(mockSecretManager, nil).AnyTimes()
   139  	mockGCP.EXPECT().GetContainerClient(gomock.Any(), gomock.Any()).Return(mockContainer, nil).AnyTimes()
   140  	mockGCP.EXPECT().GetComputeClient(gomock.Any(), gomock.Any()).Return(mockCompute, nil).AnyTimes()
   141  
   142  	appConfig := types.Config{
   143  		BSP: bsltypes.BSPConfig{
   144  			Root:     "/customers/",
   145  			Endpoint: bspMockServer.URL,
   146  			ResetURL: testResetURL,
   147  		},
   148  		Bff:     types.BffConfig{TopLevelProjectID: "test-org"},
   149  		Chariot: types.ChariotConfig{},
   150  		Okta: types.OktaConfig{
   151  			OktaIssuer: "",
   152  			ClientID:   "abc123",
   153  		},
   154  	}
   155  
   156  	mockOktaServer := okta.MockServer(&appConfig.Okta)
   157  
   158  	hc, _ := iamutils.NewIAMTestServer("projects/test-org", testProject, testServiceAccountEmail, testOauth2ClientID)
   159  	iamHTTPClient := option.WithHTTPClient(hc)
   160  
   161  	seededPostgres, err = seededpostgres.New()
   162  	if err != nil {
   163  		mockOktaServer.Close()
   164  		return nil, err
   165  	}
   166  	db, err := seededPostgres.DB()
   167  	if err != nil {
   168  		_ = seededPostgres.Close()
   169  		mockOktaServer.Close()
   170  		return nil, err
   171  	}
   172  
   173  	// Insert current version as new latest store version
   174  	versionTag := version.New().SemVer
   175  	major, minor, patch, err := version.New().SemVerMajorMinorPatch()
   176  	if err != nil {
   177  		_ = seededPostgres.Close()
   178  		mockOktaServer.Close()
   179  		return nil, err
   180  	}
   181  	if _, err = db.Exec(edgesql.AddCurrentVersionToAvailableArtifacts, fleet.Store, versionTag, major, minor, patch); err != nil {
   182  		_ = seededPostgres.Close()
   183  		mockOktaServer.Close()
   184  		return nil, err
   185  	}
   186  	if _, err = db.Exec(edgesql.UpdateLatestAvailableArtifact, fleet.Store, major, minor, patch); err != nil {
   187  		_ = seededPostgres.Close()
   188  		mockOktaServer.Close()
   189  		return nil, err
   190  	}
   191  	if _, err = db.Exec(edgesql.UpdateClusterFleetVersion, testBootstrapClusterID, versionTag); err != nil {
   192  		_ = seededPostgres.Close()
   193  		mockOktaServer.Close()
   194  		return nil, err
   195  	}
   196  	if _, err = db.Exec(edgesql.UpdateClusterFleetVersion, testBootstrapInactiveClusterID, versionTag); err != nil {
   197  		_ = seededPostgres.Close()
   198  		mockOktaServer.Close()
   199  		return nil, err
   200  	}
   201  
   202  	secret := &bsl.AccessKey{SecretKey: "testPassword", SharedKey: "testUsername"}
   203  	bslClient := bsl.NewBSLClient(appConfig.BSP, func(_ context.Context, _ string) (*bsl.AccessKey, error) { return secret, nil })
   204  	oktaClient := okta.New(appConfig.Okta)
   205  	ac := mocks.NewMockArtifactRegistryClient(MockCtrl)
   206  	path, err := fixtures.Layout()
   207  	if err != nil {
   208  		mockOktaServer.Close()
   209  		return nil, err
   210  	}
   211  	bsl, err := path.Get(name.MustParseReference("edge-bsl:latest"))
   212  	if err != nil {
   213  		mockOktaServer.Close()
   214  		return nil, err
   215  	}
   216  	p, err := pallet.New(bsl)
   217  	if err != nil {
   218  		mockOktaServer.Close()
   219  		return nil, err
   220  	}
   221  	ac.EXPECT().
   222  		Get(gomock.Any(), gomock.Any(), gomock.Any()).
   223  		Return(p, nil).AnyTimes()
   224  	//defer db.Close()
   225  	clusterLabelSvc := clustersvc.NewLabelService(db)
   226  	gcpService := services.NewGcpService(mockGCP, "top-level-project", mockBigQuery)
   227  	chariotService := services.NewChariotService(topLevelProjectID, testChariotPubsubTopic, chariotClient)
   228  	roleService := services.NewRoleService(appConfig.BSP, bslClient)
   229  	bannerService := services.NewBannerService(mockGkeClient, chariotService, bslClient, "top-level-project", db, defaultCfg)
   230  	userManagementService := services.NewUserManagementService(appConfig, bslClient, oktaClient, roleService, bannerService)
   231  	secretService := services.NewSecretService(mockGkeClient, chariotService, gcpService, mockBigQuery)
   232  	iamService := services.NewIAMService(iamHTTPClient)
   233  	bslSiteService := services.NewBSLSiteService(bslClient, db)
   234  	artifactsService := artifacts.NewArtifactsService(db, clusterLabelSvc)
   235  	labelService := services.NewLabelService(artifactsService, db)
   236  	tenantService := services.NewTenantService(db, bslClient, &appConfig.BSP)
   237  	clusterConfigService := services.NewClusterConfigService(db)
   238  	terminalService := services.NewTerminalServiceBQ(db, mockBigQuery, labelService)
   239  	compatibilityService := services.NewCompatibilityService(db)
   240  	storeClusterService := services.NewStoreClusterService(mockGkeClient, mockBigQuery, db, chariotService, terminalService, compatibilityService)
   241  	bootstrapService := services.NewBootstrapService("top-level-project", ac, db)
   242  	terminalLabelService := services.NewTerminalLabelService(db, chariotService, terminalService, storeClusterService, labelService)
   243  	activationCodeService := edgenode.NewActivationCodeService(db, terminalService, storeClusterService, clusterConfigService, secretService, gcpService, bannerService)
   244  	registrationService := services.NewRegistrationService(mockGkeClient, topLevelProjectID, secretService, gcpService, bslSiteService, iamService, db, chariotService, terminalService, activationCodeService, clusterLabelSvc, labelService)
   245  	helmService := services.NewHelmService(&appConfig, chariotService, gcpService, db, mockBigQuery, mockCompatibility)
   246  	edgeAgentService := services.NewEdgeAgentService(edgeAgentClientApi.EdgeAgentTopicAndOwner)
   247  	virtualMachineService := services.NewVirtualMachineService(db)
   248  	namespaceService := services.NewNamespaceService(db)
   249  	artifactRegistryService := services.NewArtifactRegistryService(db)
   250  	clusterSecretService := clustersecrets.NewClusterSecretService(db, gcpService, &config.Config)
   251  	kinformService := kinform.New(db)
   252  	vmStatusService := virtualmachine.NewVirtualMachineStatusService(db, kinformService)
   253  
   254  	resolver := &resolver.Resolver{
   255  		GKEClient:                   mockGkeClient,
   256  		UserManagementService:       userManagementService,
   257  		SecretService:               secretService,
   258  		RoleService:                 roleService,
   259  		HelmService:                 helmService,
   260  		GCPService:                  gcpService,
   261  		GCPClientService:            mockGCP,
   262  		BannerService:               bannerService,
   263  		RegistrationService:         registrationService,
   264  		StoreClusterService:         storeClusterService,
   265  		BSLSiteService:              bslSiteService,
   266  		IAMService:                  iamService,
   267  		BootstrapService:            bootstrapService,
   268  		ChariotService:              chariotService,
   269  		LabelService:                labelService,
   270  		TenantService:               tenantService,
   271  		Config:                      &appConfig,
   272  		TerminalService:             terminalService,
   273  		ClusterConfigService:        clusterConfigService,
   274  		TerminalLabelService:        terminalLabelService,
   275  		VirtualMachineService:       virtualMachineService,
   276  		ArtifactsService:            artifactsService,
   277  		NamespaceService:            namespaceService,
   278  		CompatibilityService:        compatibilityService,
   279  		ArtifactRegistryService:     artifactRegistryService,
   280  		ActivationCodeService:       activationCodeService,
   281  		VirtualMachineStatusService: vmStatusService,
   282  		KinformService:              kinformService,
   283  		ClusterSecretService:        clusterSecretService,
   284  		EdgeAgentService:            edgeAgentService,
   285  	}
   286  
   287  	noAuthTest := func(ctx context.Context, _ interface{}, next graphql.Resolver, _ string) (res interface{}, err error) {
   288  		return next(ctx)
   289  	}
   290  
   291  	gqlConfig := generated.Config{Resolvers: resolver}
   292  	gqlConfig.Directives.HasRole = resolver.HasRole()
   293  	gqlConfig.Directives.HasBannerAccess = noAuthTest
   294  	gqlConfig.Directives.HasBannerAccessInput = noAuthTest
   295  	gqlConfig.Directives.HasClusterAccess = noAuthTest
   296  	gqlConfig.Directives.HasClusterAccessInput = noAuthTest
   297  	gqlConfig.Directives.HasHelmWorkloadAccess = noAuthTest
   298  	gqlConfig.Directives.HasHelmWorkloadAccessInput = noAuthTest
   299  	gqlConfig.Directives.HasLabelAccessInput = noAuthTest
   300  	gqlConfig.Directives.HasLabelAccess = noAuthTest
   301  	gqlConfig.Directives.HasTerminalAccess = noAuthTest
   302  	gqlConfig.Directives.HasTerminalAccessInput = noAuthTest
   303  	gqlConfig.Directives.CanAssignRole = resolver.CanAssignRole()
   304  	srv := handler.NewDefaultServer(generated.NewExecutableSchema(gqlConfig))
   305  	srv.Use(&apierror.Extension{})
   306  
   307  	//todo figure out why this is needed and fix it
   308  	testHelmChart = "test-helm-chart1"
   309  
   310  	// use super admin permission for testing, web can later change permission at request level, see auth_service_test.go
   311  	token, err := middleware.CreateToken(testUser, testEmail, testOrg, jwtSecret, []string{superAdminRole, edgeLeadsRole}, "bslToken", "bsl", "")
   312  	if err != nil {
   313  		_ = seededPostgres.Close()
   314  		mockOktaServer.Close()
   315  		return nil, err
   316  	}
   317  	if err = testSetup(); err != nil {
   318  		_ = seededPostgres.Close()
   319  		mockOktaServer.Close()
   320  		return nil, err
   321  	}
   322  
   323  	unWrap := func(f gin.HandlerFunc) func(http.Handler) http.Handler {
   324  		return func(h http.Handler) http.Handler {
   325  			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   326  				c, _ := gin.CreateTestContext(w)
   327  				c.Request = r
   328  				f(c)
   329  				h.ServeHTTP(w, r.WithContext(c.Request.Context()))
   330  			})
   331  		}
   332  	}
   333  	handler := unWrap(middleware.AuthMiddleware(jwtSecret, totpSecret, db))(srv)
   334  	ResolverClient = client.New(handler, client.AddHeader("Authorization", "Bearer "+token))
   335  	testTime := fmt.Sprintf("%d", time.Now().UnixNano())
   336  	f := framework.New("edge-backend-unit")
   337  	return &Suite{
   338  		Framework:     f,
   339  		client:        runtimeClient,
   340  		ctx:           context.Background(),
   341  		projectID:     projectID,
   342  		testBannerEU:  &testApi.TestBannerEU,
   343  		testTime:      testTime,
   344  		ChariotClient: chariotClient,
   345  		Resolver:      resolver,
   346  		DB:            db,
   347  		Config:        config,
   348  	}, nil
   349  }
   350  
   351  func createChariotV2TestTopic() (option.ClientOption, error) {
   352  	chariotPubsubClient, err := chariotClientApiTestutils.NewMockPubsubServer()
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  	_, err = chariotClientApiTestutils.CreateMockTopic(context.Background(), topLevelProjectID, testChariotPubsubTopic, chariotPubsubClient)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  	go func() {
   361  		err := chariotClientApiTestutils.CreateMockSubscription(context.Background(), nil, topLevelProjectID, testChariotPubsubTopic, testChariotPubsubSubscription, 20*time.Second, "", func(msg *pubSub.Message) {
   362  			message := &chariotAPI.ChariotMessage{}
   363  			err := json.Unmarshal(msg.Data, message)
   364  			if err != nil {
   365  				fmt.Println(err)
   366  			}
   367  			fmt.Printf("Chariot Message: %v\n", message)
   368  			for _, t := range message.Objects {
   369  				rawDecodedText, _ := base64.StdEncoding.DecodeString(t)
   370  				resource := &unstructured.Unstructured{}
   371  				_ = resource.UnmarshalJSON(rawDecodedText)
   372  				err = chariotAction(context.Background(), message.Operation, resource)
   373  				fmt.Println("PublishMessage", resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetLabels(), resource.GetResourceVersion())
   374  				if err != nil {
   375  					fmt.Println(err)
   376  				}
   377  				if resource.GetKind() == "Cluster" && message.Operation == "DELETE" {
   378  					ClusterDeletedCount++
   379  				}
   380  			}
   381  		}, chariotPubsubClient)
   382  		if err != nil {
   383  			fmt.Println(err)
   384  		}
   385  	}()
   386  	return chariotPubsubClient, nil
   387  }
   388  
   389  func chariotAction(ctx context.Context, operation string, un *unstructured.Unstructured) error {
   390  	switch operation {
   391  	case "update", "UPDATE":
   392  		un.SetCreationTimestamp(metav1.Time{})
   393  		//un.SetResourceVersion("")
   394  		//un.SetUID("")
   395  		//un.SetGeneration(0)
   396  		//un.SetSelfLink("")
   397  		err = runtimeClient.Update(ctx, un)
   398  	case "delete", "DELETE":
   399  		err = runtimeClient.Delete(ctx, un)
   400  	default:
   401  		err = runtimeClient.Create(ctx, un)
   402  	}
   403  	return err
   404  }
   405  
   406  func createMockBigQuery() clients.BQClient {
   407  	mockBigQuery := mocks.NewMockBQClient(MockCtrl)
   408  	//mockBigQuery.EXPECT().Read(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, query string) ([]string, error) {
   409  	//	return bigQueryDataRetrieval(ctx, query)
   410  	//}).AnyTimes()
   411  	//todo convert this to work for getKubeResource
   412  	mockBigQuery.EXPECT().GetKubeResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, _ string, cluster *model.Cluster, input model.LoqRequest) ([]string, error) {
   413  		return bigQueryDataRetrieval(ctx, cluster, input)
   414  	}).AnyTimes()
   415  	return mockBigQuery
   416  }
   417  
   418  func createMockComputeService() *mocks.MockComputeService {
   419  	mockCompute := mocks.NewMockComputeService(MockCtrl)
   420  	mockCompute.EXPECT().GetZones(gomock.Any()).Return(&compute.ZoneList{Items: []*compute.Zone{{Name: testClusterZone}, {Name: "us-east1-c"}}}, nil).AnyTimes()
   421  	mockCompute.EXPECT().GetMachineTypes(gomock.Any(), testClusterZone).Return(&compute.MachineTypeList{
   422  		Items: []*compute.MachineType{{Name: testClusterMachineType, GuestCpus: 16, MemoryMb: 64 * 1024}, {Name: "c2-standard-8", GuestCpus: 8, MemoryMb: 32 * 1024}},
   423  	}, nil).AnyTimes()
   424  	mockCompute.EXPECT().GetMachineTypes(gomock.Any(), "bad-zone").Return(nil, k8sErrors.NewNotFound(schema.GroupResource{}, "")).AnyTimes()
   425  	mockCompute.EXPECT().GetMachineType(gomock.Any(), testClusterZone, testClusterMachineType).Return(&compute.MachineType{Name: testClusterMachineType, GuestCpus: 16, MemoryMb: 64 * 1024}, nil).AnyTimes()
   426  	mockCompute.EXPECT().GetMachineType(gomock.Any(), testClusterZone, "bad-machine-type").Return(nil, k8sErrors.NewNotFound(schema.GroupResource{}, "")).AnyTimes()
   427  	return mockCompute
   428  }
   429  
   430  func mockeGKEContainer() *mocks.MockContainerService {
   431  	mockContainer := mocks.NewMockContainerService(MockCtrl)
   432  	mockContainer.EXPECT().GetServerConfig(gomock.Any(), testClusterZone).Return(&container.ServerConfig{ValidMasterVersions: []string{"1.19.10-gke.1600", "1.19.10-gke.1000"}}, nil).AnyTimes()
   433  	mockContainer.EXPECT().GetServerConfig(gomock.Any(), "bad-zone").Return(nil, k8sErrors.NewNotFound(schema.GroupResource{}, "")).AnyTimes()
   434  	return mockContainer
   435  }
   436  
   437  func createGKEMockClient() *mocks.MockGkeClient {
   438  	mockGkeClient := mocks.NewMockGkeClient(MockCtrl)
   439  	mockGkeClient.EXPECT().GetConfigForCluster(gomock.Any(), mapper.CreateGKECluster(&testRegion, &testOrg)).Return(&rest.Config{
   440  		Host: "http://localhost:8080",
   441  		TLSClientConfig: rest.TLSClientConfig{
   442  			CAData: []byte("CAData"),
   443  		},
   444  	}, nil).AnyTimes()
   445  	mockGkeClient.EXPECT().GetRuntimeClient(gomock.Any(), mapper.CreateGKECluster(&badCluster, &testOrg)).Return(nil, k8sErrors.NewNotFound(schema.GroupResource{}, "")).AnyTimes()
   446  	mockGkeClient.EXPECT().GetRuntimeClient(gomock.Any(), gomock.Any()).Return(runtimeClient, nil).AnyTimes()
   447  	return mockGkeClient
   448  }
   449  
   450  func createMockCompatibilityService() *mocks.MockCompatibilityService {
   451  	mockCompatibility := mocks.NewMockCompatibilityService(MockCtrl)
   452  	mockCompatibility.EXPECT().IsCompatible(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes()
   453  	return mockCompatibility
   454  }
   455  
   456  func createMockForSecretManager() *mocks.MockSecretManagerService {
   457  	mockSecretManager := mocks.NewMockSecretManagerService(MockCtrl)
   458  	mockSecretManager.EXPECT().AddSecret(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   459  		DoAndReturn(func(_ context.Context, secretID string, secretValue []byte, labels map[string]string, _ bool, _ *time.Time, _ string) error {
   460  			return testutils.AddToSecretManager(secretValue, secretID, testOrg, labels)
   461  		}).AnyTimes()
   462  	mockSecretManager.EXPECT().GetSecret(gomock.Any(), gomock.Any()).
   463  		DoAndReturn(func(_ context.Context, name string) (*secretmanagerpb.Secret, error) {
   464  			result, err := testutils.GetFromSecretManager(testOrg, name)
   465  			if err != nil {
   466  				return nil, err
   467  			}
   468  			return result[0], err
   469  		}).AnyTimes()
   470  	mockSecretManager.EXPECT().DeleteSecret(gomock.Any(), gomock.Any()).
   471  		DoAndReturn(func(_ context.Context, name string) error {
   472  			return testutils.DeleteFromSecretManager(testOrg, name)
   473  		}).AnyTimes()
   474  	mockSecretManager.EXPECT().GetLatestSecretValue(gomock.Any(), gomock.Any()).
   475  		DoAndReturn(func(_ context.Context, secretID string) ([]byte, error) {
   476  			s, err := testutils.GetSecretInfoFromSecretManager(testOrg, secretID)
   477  			return s[0].SecretValue, err
   478  		}).AnyTimes()
   479  	mockSecretManager.EXPECT().GetLatestSecretValueInfo(gomock.Any(), gomock.Any()).
   480  		DoAndReturn(func(_ context.Context, secretID string) (*secretmanagerpb.SecretVersion, error) {
   481  			s, err := testutils.GetSecretInfoFromSecretManager(testOrg, secretID)
   482  			if err != nil {
   483  				return nil, err
   484  			}
   485  			return s[0].SecretVersion, err
   486  		}).AnyTimes()
   487  	mockSecretManager.EXPECT().ListSecrets(gomock.Any(), gomock.Any()).
   488  		DoAndReturn(func(_ context.Context, pageToken string) ([]*secretmanagerpb.Secret, string, error) {
   489  			result, err := testutils.GetFromSecretManager(testOrg, pageToken)
   490  			return result, projectID, err
   491  		}).AnyTimes()
   492  	mockSecretManager.EXPECT().GetProjectID().Return(testOrg).AnyTimes()
   493  	return mockSecretManager
   494  }
   495  
   496  func testSetup() error {
   497  	if err := runtimeClient.Create(context.Background(), &corev1.Namespace{
   498  		ObjectMeta: metav1.ObjectMeta{Name: "flux-system"},
   499  	}); err != nil {
   500  		return err
   501  	}
   502  	if err := runtimeClient.Create(context.Background(), getDefaultServiceAccountSecret()); err != nil {
   503  		return err
   504  	}
   505  	if err := runtimeClient.Create(context.Background(), getHelmRelease()); err != nil {
   506  		return err
   507  	}
   508  	if err := runtimeClient.Create(context.Background(), newBSLUserSecret("edge-system", testOrg)); err != nil {
   509  		return err
   510  	}
   511  	if err := runtimeClient.Create(context.Background(), getTestProject(testOrg)); err != nil {
   512  		return err
   513  	}
   514  	if err := runtimeClient.Create(context.Background(), getEdgeInfoConfigmap()); err != nil {
   515  		return err
   516  	}
   517  	return err
   518  }
   519  
   520  func getEdgeInfoConfigmap() *corev1.ConfigMap {
   521  	return info.BuildConfigMap("test-org", testStore, "store", testRegion, "test-org", "fleet", topLevelProjectID, "3396a52c-6a22-4049-9593-5a63b596a100", "3396a52c-6a22-4049-9593-5a63b596a201", "test-env-url")
   522  }
   523  
   524  // Test Object: The objects already exists before bff runs
   525  func getDefaultServiceAccountSecret() *corev1.Secret {
   526  	data := make(map[string][]byte)
   527  	sa, _ := json.Marshal(&model.ServiceAccount{
   528  		ProjectID: &projectID,
   529  	})
   530  	data["key.json"] = sa
   531  	return &corev1.Secret{
   532  		TypeMeta: metav1.TypeMeta{
   533  			APIVersion: "v1",
   534  			Kind:       "Secret",
   535  		},
   536  		ObjectMeta: metav1.ObjectMeta{
   537  			Namespace:         mapper.SANamespace,
   538  			Name:              mapper.SAName,
   539  			CreationTimestamp: metav1.Now(),
   540  		},
   541  		Data: data,
   542  	}
   543  }
   544  
   545  func getHelmRelease() *helmApi.HelmRelease {
   546  	return &helmApi.HelmRelease{
   547  		ObjectMeta: metav1.ObjectMeta{
   548  			Name:      "test-helm-release",
   549  			Namespace: "flux-system",
   550  		},
   551  		Spec: helmApi.HelmReleaseSpec{
   552  			Interval: metav1.Duration{
   553  				Duration: time.Duration(2) * time.Minute,
   554  			},
   555  			ReleaseName:     "test-helm-release",
   556  			TargetNamespace: "flux-system",
   557  			Chart: &helmApi.HelmChartTemplate{
   558  				Spec: helmApi.HelmChartTemplateSpec{
   559  					Chart:   "podinfo",
   560  					Version: "1.0",
   561  					SourceRef: helmApi.CrossNamespaceObjectReference{
   562  						Kind: "HelmRepository",
   563  						Name: "test-repo",
   564  					},
   565  				},
   566  			},
   567  		},
   568  	}
   569  }
   570  
   571  // newBSLUserSecret return a new initialized secret.
   572  func newBSLUserSecret(ns, name string) *corev1.Secret {
   573  	return &corev1.Secret{
   574  		TypeMeta: metav1.TypeMeta{
   575  			APIVersion: "v1",
   576  			Kind:       "Secret",
   577  		},
   578  		ObjectMeta: metav1.ObjectMeta{
   579  			Namespace: ns,
   580  			Name:      name,
   581  		},
   582  		Data: map[string][]byte{
   583  			bsl.SharedKey: []byte("testSharedKey"),
   584  			bsl.SecretKey: []byte("testSecretKey"),
   585  		},
   586  	}
   587  }
   588  
   589  // Test Object
   590  func getTestProject(name string) *resourceApi.Project {
   591  	return &resourceApi.Project{
   592  		ObjectMeta: metav1.ObjectMeta{
   593  			Name:      name,
   594  			Namespace: name,
   595  		},
   596  		Spec: resourceApi.ProjectSpec{
   597  			BillingAccountRef: &v1alpha1.ResourceRef{
   598  				Name: "billingAccount",
   599  			},
   600  			FolderRef: &v1alpha1.ResourceRef{
   601  				Name: "folderRef",
   602  			},
   603  			Name:       name,
   604  			ResourceID: &name,
   605  		},
   606  	}
   607  }
   608  
   609  func bigQueryDataRetrieval(ctx context.Context, cluster *model.Cluster, query model.LoqRequest) ([]string, error) {
   610  	// exclude delete label so only resources that have not been deleted are returned
   611  	key := &runtimeclient.ObjectKey{}
   612  	if query.Name == nil && query.Namespace == nil {
   613  		key = nil
   614  	}
   615  	if query.Namespace != nil {
   616  		key.Namespace = *query.Namespace
   617  	}
   618  	if query.Name != nil {
   619  		key.Name = *query.Name
   620  	}
   621  	gvk := &schema.GroupVersionKind{
   622  		Kind:    query.Kind,
   623  		Group:   query.Group,
   624  		Version: query.Version,
   625  	}
   626  	excludedLabels := []string{"delete"}
   627  	newReq, err := labels.NewRequirement("type", selection.NotIn, excludedLabels)
   628  	if err != nil {
   629  		return nil, err
   630  	}
   631  	newSelector := labels.NewSelector()
   632  	newSelector.Add(*newReq)
   633  	matcher := runtimeclient.MatchingLabelsSelector{Selector: newSelector}
   634  	switch {
   635  	case (key == nil || (query.Namespace == nil && query.Name == nil)) && query.Kind != "HelmRelease":
   636  		list := &unstructured.UnstructuredList{}
   637  		list.SetGroupVersionKind(*gvk)
   638  		if err := runtimeClient.List(ctx, list, matcher); err != nil {
   639  			return nil, err
   640  		}
   641  		return unstructuredutil.UnstructuredListToStrings(list)
   642  	case query.Kind == "ClusterStatus":
   643  		return handleStoreStatusQuery(key)
   644  	case query.Kind == "HelmRelease":
   645  		list := &unstructured.UnstructuredList{}
   646  		list.SetGroupVersionKind(*gvk)
   647  		if err := runtimeClient.List(ctx, list, runtimeclient.InNamespace("flux-system"), matcher); err != nil {
   648  			return nil, err
   649  		}
   650  		return unstructuredutil.UnstructuredListToStrings(list)
   651  	case query.Kind == "ConfigMap" && key.Name == bsl.BSLInfoConfigMapName:
   652  		return handleConfigMapQuery(cluster.ClusterEdgeID, cluster.Name)
   653  	case utils.Contains([]string{"Banner", "GKECluster", "Cluster", "ConfigMap"}, gvk.GroupKind().Kind):
   654  		fmt.Println("Cluster Scope", gvk, key, "delete")
   655  		fallthrough
   656  	case key.Name == "" && key.Namespace != "":
   657  		list := &unstructured.UnstructuredList{}
   658  		list.SetGroupVersionKind(*gvk)
   659  		if err := runtimeClient.List(ctx, list, runtimeclient.InNamespace(key.Namespace), matcher); err != nil {
   660  			return nil, err
   661  		}
   662  		return unstructuredutil.UnstructuredListToStrings(list)
   663  	default:
   664  		un := &unstructured.Unstructured{}
   665  		un.SetGroupVersionKind(*gvk)
   666  		if err := runtimeClient.Get(ctx, *key, un); err != nil {
   667  			return nil, err
   668  		}
   669  		data, err := un.MarshalJSON()
   670  		return []string{string(data)}, err
   671  	}
   672  }
   673  
   674  func handleStoreStatusQuery(key *runtimeclient.ObjectKey) ([]string, error) {
   675  	nodeVersion := "v1.23.6"
   676  	if key.Name == ctlfish.ClusterStatusName {
   677  		testSyncInfo := monitor.SyncInfo{
   678  			LastUpdated:   "test-last-updated",
   679  			Revision:      "test-revision",
   680  			StatusMessage: "test-status-message",
   681  			Error:         false,
   682  			Suspended:     true,
   683  		}
   684  		buckets := map[string]monitor.BucketInfo{
   685  			"test-bucket-1": {
   686  				Excludes:   "test-excludes",
   687  				BucketName: "test-bucket-name",
   688  				FluxStatus: testSyncInfo,
   689  			},
   690  		}
   691  		kustomizations := map[string]monitor.KustomizationInfo{
   692  			"test-kustomization-1": {Path: "test-path-1", Source: "test-source-1", FluxStatus: testSyncInfo},
   693  			"test-kustomization-2": {Path: "test-path-2", Source: "test-source-2", FluxStatus: testSyncInfo},
   694  		}
   695  		status := &monitor.ClusterStatus{
   696  			Status:         "Ready",
   697  			NodeVersion:    nodeVersion,
   698  			Buckets:        buckets,
   699  			Kustomizations: kustomizations,
   700  		}
   701  		data, err := json.Marshal(status)
   702  		return []string{string(data)}, err
   703  	}
   704  	return []string{}, fmt.Errorf("%v store status not found", key)
   705  }
   706  
   707  func handleConfigMapQuery(clusterEdgeID, clusterName string) ([]string, error) {
   708  	if clusterEdgeID == "5bc12c67-d9b0-4f13-a6d4-4852b0c11291" || clusterName == "test_cluster-3" {
   709  		return getConfigMap("test_bsl_site_id-3", "")
   710  	} else if clusterEdgeID == testClusterEdgeID2 || clusterName == "test_cluster-2" {
   711  		return getConfigMap("test_bsl_site_id-2", "")
   712  	} else if clusterEdgeID == testClusterEdgeID || clusterName == "test_cluster02" {
   713  		return getConfigMap("test_bsl_site_id", "test mismatch in site description")
   714  	}
   715  	return []string{}, fmt.Errorf("bsl-info config map not found, cluster: %s, %s", clusterEdgeID, clusterName)
   716  }
   717  
   718  func getConfigMap(bslSiteID, description string) ([]string, error) {
   719  	configMap := bsl.BuildConfigMap("test-store", "test-enterprise-unit-name", "", services.DefaultLatitude, services.DefaultLongitude, &bslSiteID)
   720  	if description != "" {
   721  		configMap.Data[bsl.BSLSiteDescription] = description
   722  	}
   723  	data, err := json.Marshal(configMap)
   724  	return []string{string(data)}, err
   725  }
   726  

View as plain text