...

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

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

     1  package integration_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"fmt"
     7  
     8  	"github.com/golang/mock/gomock"
     9  	"github.com/google/uuid"
    10  	"k8s.io/utils/ptr"
    11  
    12  	"edge-infra.dev/pkg/edge/api/graph/model"
    13  	"edge-infra.dev/pkg/edge/api/mocks"
    14  	"edge-infra.dev/pkg/edge/api/services/edgenode"
    15  	"edge-infra.dev/pkg/edge/api/services/edgenode/activationcode"
    16  	"edge-infra.dev/pkg/edge/api/services/edgenode/common"
    17  	"edge-infra.dev/pkg/lib/crypto"
    18  	pxe "edge-infra.dev/pkg/sds/ien/k8s/controllers/pxe/common"
    19  	"edge-infra.dev/test/framework/integration"
    20  )
    21  
    22  const (
    23  	// for use in activation_code_test.go (terminal activation)
    24  	activationClusterEdgeID = "d7e6b441-2781-49f0-af49-24b7acef586c"
    25  	// for use in activation_code_test.go (terminal activation)
    26  	activationTerminalID = "84defb06-85b8-4db4-b734-f3dc100853ea"
    27  	// for use in activation_code_test.go (terminal activation)
    28  	activationProjectID = "test-org"
    29  	// for use in activation_code_test.go (terminal activation)
    30  	activationBannerID = "3396a52c-6a22-4049-9593-5a63b596a101"
    31  )
    32  
    33  func (s *Suite) initEdgeNodeServices() (*mocks.MockSecretService, *mocks.MockGCPService, common.ActivationCode) {
    34  	mock := gomock.NewController(s.T())
    35  	secretSvc := mocks.NewMockSecretService(mock)
    36  	gcpSvc := mocks.NewMockGCPService(mock)
    37  	activationSvc := edgenode.NewActivationCodeService(s.DB, s.Resolver.TerminalService, s.Resolver.StoreClusterService, s.Resolver.ClusterConfigService, secretSvc, gcpSvc, s.Resolver.BannerService)
    38  	return secretSvc, gcpSvc, activationSvc
    39  }
    40  
    41  func (s *Suite) TestSyncToStore() {
    42  	integration.SkipIf(s.Framework)
    43  
    44  	// initialise test services
    45  	_, gcpSvc, activationSvc := s.initEdgeNodeServices()
    46  
    47  	// set up test resources
    48  	terminalID := uuid.NewString()
    49  	cluster := &model.Cluster{ProjectID: activationProjectID}
    50  	code := "ACTIVATION_CODE"
    51  
    52  	expectSyncToStore(gcpSvc, terminalID, activationProjectID)
    53  	s.NoError(err)
    54  	err = activationSvc.SyncToStore(context.Background(), terminalID, cluster, code)
    55  	s.NoError(err)
    56  }
    57  
    58  // expectSyncToStore sets up the expectations for the SyncToStore service function
    59  func expectSyncToStore(gcpSvc *mocks.MockGCPService, terminalID string, projectID string) {
    60  	secretName := fmt.Sprintf("%s-%s", activationcode.SecretType, terminalID)
    61  	gcpSvc.EXPECT().AddSecret(gomock.Any(), secretName, activationcode.Workload, activationcode.SecretType, gomock.Any(), projectID, ptr.To(activationcode.Workload), nil).Return(nil)
    62  }
    63  
    64  func expectFetchFromSecret(gcpSvc *mocks.MockGCPService, secretResp []*model.SecretManagerResponse, terminalID string) {
    65  	secretName := fmt.Sprintf("%s-%s", activationcode.SecretType, terminalID)
    66  	gcpSvc.EXPECT().GetSecrets(gomock.Any(), &secretName, ptr.To(activationcode.Workload), ptr.To(activationcode.SecretType), true, activationProjectID).Return(secretResp, nil)
    67  }
    68  
    69  func (s *Suite) TestFetchFromSecret() {
    70  	integration.SkipIf(s.Framework)
    71  
    72  	_, gcpSvc, activationSvc := s.initEdgeNodeServices()
    73  
    74  	terminalID := activationTerminalID
    75  	secretName := fmt.Sprintf("%s-%s", activationcode.SecretType, terminalID)
    76  
    77  	testCases := []struct {
    78  		secretResp []*model.SecretManagerResponse
    79  		err        error
    80  	}{
    81  		{ // need secret's values
    82  			secretResp: []*model.SecretManagerResponse{
    83  				{Name: secretName},
    84  			},
    85  			err: activationcode.ErrInvalidActivationSecret,
    86  		},
    87  		{ // cannot have no secrets
    88  			secretResp: []*model.SecretManagerResponse{},
    89  			err:        activationcode.ErrInvalidActivationSecretCount,
    90  		},
    91  		{ // cannot have more than 1 secret
    92  			secretResp: []*model.SecretManagerResponse{
    93  				{Name: secretName},
    94  				{Name: secretName},
    95  			},
    96  			err: activationcode.ErrInvalidActivationSecretCount,
    97  		},
    98  		{ // secret cannot have multiple values
    99  			secretResp: []*model.SecretManagerResponse{
   100  				{
   101  					Name: secretName,
   102  					Values: []*model.KeyValuesOutput{
   103  						{
   104  							Key:   "key1",
   105  							Value: "value1",
   106  						},
   107  						{
   108  							Key:   "key2",
   109  							Value: "value2",
   110  						},
   111  					},
   112  				},
   113  			},
   114  			err: activationcode.ErrInvalidActivationSecret,
   115  		},
   116  		{ // valid
   117  			secretResp: []*model.SecretManagerResponse{
   118  				{
   119  					Name: secretName,
   120  					Values: []*model.KeyValuesOutput{
   121  						{
   122  							Key:   "key1",
   123  							Value: "value1",
   124  						},
   125  					},
   126  				},
   127  			},
   128  			err: nil,
   129  		},
   130  	}
   131  
   132  	for _, test := range testCases {
   133  		expectFetchFromSecret(gcpSvc, test.secretResp, terminalID)
   134  		_, err := activationSvc.FetchFromSecret(context.Background(), terminalID)
   135  		s.ErrorIs(err, test.err)
   136  	}
   137  }
   138  
   139  func (s *Suite) TestRefreshActivationCode() {
   140  	integration.SkipIf(s.Framework)
   141  
   142  	// initialise test services
   143  	_, gcpSvc, activationSvc := s.initEdgeNodeServices()
   144  	terminalID := activationTerminalID
   145  
   146  	expectSyncToStore(gcpSvc, terminalID, activationProjectID)
   147  
   148  	// hashed version is seeded for this test terminal
   149  	existingCode := "XJTQ8UKN9DWNRF3"
   150  	newCode, err := activationSvc.Refresh(context.Background(), terminalID)
   151  	s.NoError(err)
   152  	s.NotEqual(existingCode, newCode)
   153  }
   154  
   155  func (s *Suite) TestCreateActivationCode() {
   156  	integration.SkipIf(s.Framework)
   157  
   158  	// initialise test services
   159  	_, gcpSvc, activationSvc := s.initEdgeNodeServices()
   160  
   161  	// set up test resources
   162  	terminal := &model.Terminal{
   163  		TerminalID:    activationTerminalID,
   164  		ClusterEdgeID: activationClusterEdgeID,
   165  	}
   166  	cluster := &model.Cluster{
   167  		ProjectID: activationProjectID,
   168  	}
   169  	code, err := crypto.GenerateRandomActivationCode()
   170  	s.NoError(err)
   171  
   172  	// set up expectations for internal call to SyncToStore
   173  	expectSyncToStore(gcpSvc, terminal.TerminalID, cluster.ProjectID)
   174  
   175  	ctx := context.Background()
   176  	err = activationSvc.Create(ctx, code, terminal)
   177  	s.NoError(err)
   178  	// check activation code correctly created in DB
   179  	dbCode, err := activationSvc.Fetch(ctx, terminal.TerminalID)
   180  	s.NoError(err)
   181  	s.NotNil(dbCode)
   182  	s.Equal(hex.EncodeToString(code.Hashed()), *dbCode)
   183  }
   184  
   185  func expectDeleteActivationCode(gcpSvc *mocks.MockGCPService, secretSvc *mocks.MockSecretService, terminalID string, projectID string) {
   186  	secretName := fmt.Sprintf("%s-%s", activationcode.SecretType, terminalID)
   187  	gcpSvc.EXPECT().DeleteSecret(gomock.Any(), secretName, projectID).Return(true, nil)
   188  	secretSvc.EXPECT().DeleteExternalSecret(gomock.Any(), secretName, pxe.PXENamespace, projectID, gomock.Not(nil), gomock.Any(), secretName).Return(nil)
   189  }
   190  
   191  func (s *Suite) TestSyncAllToStore() {
   192  	integration.SkipIf(s.Framework)
   193  
   194  	_, gcpSvc, activationSvc := s.initEdgeNodeServices()
   195  
   196  	// set up test resources
   197  	cluster := &model.Cluster{
   198  		ClusterEdgeID: activationClusterEdgeID,
   199  		ProjectID:     activationProjectID,
   200  	}
   201  	terminalID := activationTerminalID
   202  	secretName := fmt.Sprintf("%s-%s", activationcode.SecretType, terminalID)
   203  	secretResp := []*model.SecretManagerResponse{
   204  		{
   205  			Name: secretName,
   206  			Values: []*model.KeyValuesOutput{
   207  				{
   208  					Key:   "key1",
   209  					Value: "value1",
   210  				},
   211  			},
   212  		},
   213  	}
   214  
   215  	expectFetchFromSecret(gcpSvc, secretResp, terminalID)
   216  	expectSyncToStore(gcpSvc, terminalID, cluster.ProjectID)
   217  
   218  	err := activationSvc.SyncAllToStore(context.Background(), cluster.ClusterEdgeID)
   219  	s.NoError(err)
   220  }
   221  
   222  func (s *Suite) TestMarkUsed() {
   223  	integration.SkipIf(s.Framework)
   224  
   225  	// initialise test services
   226  	secretSvc, gcpSvc, activationSvc := s.initEdgeNodeServices()
   227  
   228  	// set up test resources
   229  	terminalID := activationTerminalID
   230  	cluster := &model.Cluster{
   231  		ProjectID:    activationProjectID,
   232  		BannerEdgeID: activationBannerID,
   233  	}
   234  
   235  	expectDeleteActivationCode(gcpSvc, secretSvc, terminalID, cluster.ProjectID)
   236  
   237  	ctx := context.Background()
   238  	err := activationSvc.MarkUsed(ctx, terminalID, cluster, nil)
   239  	s.NoError(err)
   240  	// check activation code correctly reset in DB
   241  	dbCode, err := activationSvc.Fetch(ctx, terminalID)
   242  	s.NoError(err)
   243  	s.NotNil(dbCode)
   244  	s.Equal("", *dbCode)
   245  }
   246  
   247  func (s *Suite) TestCleanupStore() {
   248  	integration.SkipIf(s.Framework)
   249  
   250  	// initialise test services
   251  	secretSvc, gcpSvc, activationSvc := s.initEdgeNodeServices()
   252  
   253  	// set up test resources
   254  	cluster := &model.Cluster{
   255  		ProjectID:     activationProjectID,
   256  		ClusterEdgeID: activationClusterEdgeID,
   257  		BannerEdgeID:  activationBannerID,
   258  	}
   259  	terminalID := activationTerminalID
   260  
   261  	expectDeleteActivationCode(gcpSvc, secretSvc, terminalID, cluster.ProjectID)
   262  
   263  	err := activationSvc.CleanupStore(context.Background(), cluster)
   264  	s.NoError(err)
   265  }
   266  

View as plain text