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
24 activationClusterEdgeID = "d7e6b441-2781-49f0-af49-24b7acef586c"
25
26 activationTerminalID = "84defb06-85b8-4db4-b734-f3dc100853ea"
27
28 activationProjectID = "test-org"
29
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
45 _, gcpSvc, activationSvc := s.initEdgeNodeServices()
46
47
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
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 {
82 secretResp: []*model.SecretManagerResponse{
83 {Name: secretName},
84 },
85 err: activationcode.ErrInvalidActivationSecret,
86 },
87 {
88 secretResp: []*model.SecretManagerResponse{},
89 err: activationcode.ErrInvalidActivationSecretCount,
90 },
91 {
92 secretResp: []*model.SecretManagerResponse{
93 {Name: secretName},
94 {Name: secretName},
95 },
96 err: activationcode.ErrInvalidActivationSecretCount,
97 },
98 {
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 {
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
143 _, gcpSvc, activationSvc := s.initEdgeNodeServices()
144 terminalID := activationTerminalID
145
146 expectSyncToStore(gcpSvc, terminalID, activationProjectID)
147
148
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
159 _, gcpSvc, activationSvc := s.initEdgeNodeServices()
160
161
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
173 expectSyncToStore(gcpSvc, terminal.TerminalID, cluster.ProjectID)
174
175 ctx := context.Background()
176 err = activationSvc.Create(ctx, code, terminal)
177 s.NoError(err)
178
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
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
226 secretSvc, gcpSvc, activationSvc := s.initEdgeNodeServices()
227
228
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
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
251 secretSvc, gcpSvc, activationSvc := s.initEdgeNodeServices()
252
253
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