forked from mrz1836/codepipeline-to-github
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatus_test.go
411 lines (354 loc) · 13.6 KB
/
status_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
package main
import (
"fmt"
"os"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/codepipeline"
"github.com/aws/aws-sdk-go/service/codepipeline/codepipelineiface"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/aws/aws-sdk-go/service/kms/kmsiface"
)
// Mocking kms client
type mockKmsClient struct {
kmsiface.KMSAPI
}
// Decrypt is used for mocking a decryption of a KMS key
func (m *mockKmsClient) Decrypt(input *kms.DecryptInput) (*kms.DecryptOutput, error) {
// Invalid input
if len(input.CiphertextBlob) == 0 {
return nil, fmt.Errorf("missing text to encrypt")
}
output := &kms.DecryptOutput{
Plaintext: []byte(" some-encrypted-text\n"),
}
return output, nil
}
// Mocking pipeline client
type mockCodePipelineClient struct {
codepipelineiface.CodePipelineAPI
}
// GetPipelineExecution is a mock request for codepipeline
func (m *mockCodePipelineClient) GetPipelineExecution(input *codepipeline.GetPipelineExecutionInput) (*codepipeline.GetPipelineExecutionOutput, error) {
// Missing pipeline name
if len(aws.StringValue(input.PipelineName)) == 0 {
return nil, fmt.Errorf("aws will reject: missing pipeline name")
}
// Missing pipeline name
if len(aws.StringValue(input.PipelineExecutionId)) == 0 {
return nil, fmt.Errorf("aws will reject: missing execution id")
}
// Test nil response and no error
if aws.StringValue(input.PipelineName) == "nil" {
return nil, nil
}
// Create a valid artifact
var artifacts []*codepipeline.ArtifactRevision
if aws.StringValue(input.PipelineName) == "bad-artifact-name" {
artifacts = append(artifacts, &codepipeline.ArtifactRevision{
Name: aws.String("InvalidArtifactName"),
RevisionId: aws.String("25c0c3e61c4db2c2cde8b163b3ad096875c1ce08"),
RevisionSummary: aws.String("Some commit message"),
RevisionUrl: aws.String("https://github.com/mrz1836/codepipeline-to-github/commit/25c0c3e61c4db2c2cde8b163b3ad096875c1ce08"),
})
} else if aws.StringValue(input.PipelineName) == "bad-artifact-url" {
artifacts = append(artifacts, &codepipeline.ArtifactRevision{
Name: aws.String("InvalidArtifactName"),
RevisionId: aws.String("25c0c3e61c4db2c2cde8b163b3ad096875c1ce08"),
RevisionSummary: aws.String("Some commit message"),
RevisionUrl: aws.String("not a url"),
})
} else {
artifacts = append(artifacts, &codepipeline.ArtifactRevision{
Name: aws.String("SourceCode"),
RevisionId: aws.String("25c0c3e61c4db2c2cde8b163b3ad096875c1ce08"),
RevisionSummary: aws.String("Some commit message"),
RevisionUrl: aws.String("https://github.com/mrz1836/codepipeline-to-github/commit/25c0c3e61c4db2c2cde8b163b3ad096875c1ce08"),
})
}
defaultStatus := aws.String("InProgress")
// Change the status
if aws.StringValue(input.PipelineName) == "status-succeed" {
defaultStatus = aws.String("Succeeded")
} else if aws.StringValue(input.PipelineName) == "status-fail" {
defaultStatus = aws.String("Failure")
}
// Create a valid execution output
output := &codepipeline.GetPipelineExecutionOutput{
PipelineExecution: &codepipeline.PipelineExecution{
ArtifactRevisions: artifacts,
PipelineExecutionId: input.PipelineExecutionId,
PipelineName: input.PipelineName,
Status: defaultStatus,
},
}
return output, nil
}
// TestProcessEvent will test the ProcessEvent() method
func TestProcessEvent(t *testing.T) {
os.Clearenv()
// Create a new AWS session
if awsSession == nil {
awsSession = session.Must(session.NewSession(&aws.Config{
Region: aws.String("us-east-1"),
}))
}
t.Run("missing event detail", func(t *testing.T) {
if err := ProcessEvent(event{}); err == nil {
t.Fatal("error failed to trigger with an invalid request")
}
})
t.Run("missing param execution-id", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "",
}}
if err := ProcessEvent(ev); err == nil {
t.Fatal("error failed to trigger with an invalid request")
}
})
t.Run("missing param pipeline", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "12345678",
}}
if err := ProcessEvent(ev); err == nil {
t.Fatal("error failed to trigger with an invalid request")
}
})
t.Run("missing pipeline execution", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "12345678",
Pipeline: "12345678",
}}
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
if err := ProcessEvent(ev); err == nil {
t.Fatal("error failed to trigger with an invalid request")
}
})
t.Run("required key AWS_REGION missing value", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "12345678",
Pipeline: "12345678",
}}
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
err := ProcessEvent(ev)
if err == nil {
t.Fatal("expected error")
} else if err.Error() != "required key AWS_REGION missing value" {
t.Fatal("error expected was not the same", err.Error())
}
})
t.Run("required key APPLICATION_STAGE_NAME missing value", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "12345678",
Pipeline: "12345678",
}}
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
_ = os.Setenv("AWS_REGION", "us-east-1")
err := ProcessEvent(ev)
if err == nil {
t.Fatal("expected error")
} else if err.Error() != "required key APPLICATION_STAGE_NAME missing value" {
t.Fatal("error expected was not the same", err.Error())
}
})
t.Run("ValidationException: ExecutionID", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "12345678",
Pipeline: "12345678",
}}
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
_ = os.Setenv("AWS_REGION", "us-east-1")
_ = os.Setenv("APPLICATION_STAGE_NAME", "testing")
err := ProcessEvent(ev)
if err == nil {
t.Fatal("error was expected")
} /*else if !strings.Contains(err.Error(), "ValidationException: 1 validation error detected") {
t.Fatal("error message expected does not match", err.Error())
}*/
})
t.Run("PipelineNotFoundException: The account with id", func(t *testing.T) {
ev := event{
Detail: &detail{
ExecutionID: "a5ef215c-43b4-4513-b97f-1829f642e0b1",
Pipeline: "12345678",
}}
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
_ = os.Setenv("AWS_REGION", "us-east-1")
_ = os.Setenv("APPLICATION_STAGE_NAME", "testing")
err := ProcessEvent(ev)
if err == nil {
t.Fatal("error was expected")
} /* else if !strings.Contains(err.Error(), "PipelineNotFoundException: The account with id") {
t.Fatal("error message expected does not match", err.Error())
}*/
})
// todo: test loading configuration
// todo: test extracting the github information from pipeline
}
// TestGetExecutionOutput will test GetExecutionOutput()
func TestGetExecutionOutput(t *testing.T) {
mockPipeline := &mockCodePipelineClient{}
var tests = []struct {
pipelineName string
executionID string
expectedExecutionID string
expectedPipelineName string
expectedStatus string
expectedError bool
expectedNil bool
}{
{"some-pipeline", "12345", "12345", "some-pipeline", "InProgress", false, false},
{"", "12345", "12345", "", "InProgress", true, true},
{"some-pipeline", "", "", "some-pipeline", "InProgress", true, true},
{"nil", "12345", "12345", "nil", "InProgress", true, true},
{"status-succeed", "12345", "12345", "status-succeed", "Succeeded", false, false},
{"status-fail", "12345", "12345", "status-fail", "Failure", false, false},
}
for _, test := range tests {
response, err := getExecutionOutput(test.pipelineName, test.executionID, mockPipeline)
if err == nil && test.expectedError {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], expected to throw an error, but no error", t.Name(), test.pipelineName, test.executionID)
} else if err != nil && !test.expectedError {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], error occurred [%s]", t.Name(), test.pipelineName, test.executionID, err.Error())
} else if response == nil && !test.expectedNil {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], response was nil", t.Name(), test.pipelineName, test.executionID)
} else if response != nil && test.expectedNil {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], response was not nil", t.Name(), test.pipelineName, test.executionID)
} else if response != nil && aws.StringValue(response.PipelineExecution.PipelineName) != test.expectedPipelineName && !test.expectedError {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], expected [%s]", t.Name(), test.pipelineName, test.executionID, test.expectedPipelineName)
} else if response != nil && aws.StringValue(response.PipelineExecution.PipelineExecutionId) != test.expectedExecutionID && !test.expectedError {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], expected [%s]", t.Name(), test.pipelineName, test.executionID, test.executionID)
} else if response != nil && aws.StringValue(response.PipelineExecution.Status) != test.expectedStatus && !test.expectedError {
t.Errorf("%s Failed: codepipeline [%s] executionID [%s], expected [%s]", t.Name(), test.pipelineName, test.executionID, test.expectedStatus)
}
}
}
// TestGetArtifact will test getting an artifact from an execution output
func TestGetArtifact(t *testing.T) {
t.Parallel()
mockPipeline := &mockCodePipelineClient{}
// Test a valid pipeline response
response, err := getExecutionOutput("some-pipeline", "12345", mockPipeline)
if err != nil {
t.Fatal("error should not have occurred", err.Error())
} else if response == nil {
t.Fatal("response is nil and was expected to be a pointer")
}
artifact := getArtifact(response)
if artifact == nil {
t.Fatal("artifact was nil, expected a pointer")
}
// Test an invalid artifact name
response, _ = getExecutionOutput("bad-artifact-name", "12345", mockPipeline)
artifact = getArtifact(response)
if artifact != nil {
t.Fatal("artifact was not nil, expected artifact to be nil")
}
}
// TestGetCommit will test getting a commit from a pipeline execution
func TestGetCommit(t *testing.T) {
t.Parallel()
mockPipeline := &mockCodePipelineClient{}
// Test a valid pipeline response
response, err := getExecutionOutput("some-pipeline", "12345", mockPipeline)
if err != nil {
t.Fatal("error should not have occurred", err.Error())
} else if response == nil {
t.Fatal("response is nil and was expected to be a pointer")
}
// Valid commit artifact
commit, status, revisionURL, commitErr := getCommit("some-pipeline", "12345", mockPipeline)
if commitErr != nil {
t.Fatal("error occurred in getCommit", commitErr.Error())
} else if commit != "25c0c3e61c4db2c2cde8b163b3ad096875c1ce08" {
t.Fatal("commit value was not as expected", commit)
} else if status != "pending" {
t.Fatal("status value was not as expected", status)
} else if revisionURL == nil {
t.Fatal("url was nil, expected pointer")
} else if revisionURL.String() != "https://github.com/mrz1836/codepipeline-to-github/commit/25c0c3e61c4db2c2cde8b163b3ad096875c1ce08" {
t.Fatal("revisionURL value was not as expected", revisionURL.String())
}
// Invalid commit url
_, _, revisionURL, commitErr = getCommit("bad-artifact-url", "12345", mockPipeline)
if revisionURL != nil {
t.Fatal("revisionURL should have been nil")
} else if commitErr != nil {
t.Fatal("error should still be nil", revisionURL, commitErr)
}
}
// TestDecryptString will test decryptString()
func TestDecryptString(t *testing.T) {
t.Parallel()
mockKms := &mockKmsClient{}
// Valid decryption
decrypted, err := decryptString(mockKms, "dGhpcyBpcyBzYW5mb3VuZHJ5IGxpbnV4IHR1dG9yaWFsCg==")
if err != nil {
t.Fatal("error occurred", err.Error())
} else if decrypted != "some-encrypted-text" {
t.Fatal("value expected was wrong", decrypted)
}
// Invalid base64
_, err = decryptString(mockKms, "invalid-base-64")
if err == nil {
t.Fatal("error should have occurred")
}
// Invalid value
_, err = decryptString(mockKms, "")
if err == nil {
t.Fatal("error should have occurred")
}
}
// TestLoadConfiguration will test loadConfiguration()
func TestLoadConfiguration(t *testing.T) {
mockKms := &mockKmsClient{}
os.Clearenv()
// Invalid - missing region
err := loadConfiguration(mockKms)
if err == nil {
t.Fatal("error should have occurred")
} else if err.Error() != "required key AWS_REGION missing value" {
t.Error("error returned was not as expected", err.Error())
}
// Invalid - missing github token
_ = os.Setenv("AWS_REGION", "us-east-1")
err = loadConfiguration(mockKms)
if err == nil {
t.Fatal("error should have occurred")
} else if err.Error() != "required key GITHUB_ACCESS_TOKEN missing value" {
t.Error("error returned was not as expected", err.Error())
}
// Invalid - missing application stage
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "1234567")
err = loadConfiguration(mockKms)
if err == nil {
t.Fatal("error should have occurred")
} else if err.Error() != "required key APPLICATION_STAGE_NAME missing value" {
t.Error("error returned was not as expected", err.Error())
}
// Invalid - token is not base64
_ = os.Setenv("APPLICATION_STAGE_NAME", "development")
err = loadConfiguration(mockKms)
if err == nil {
t.Fatal("error should have occurred")
} else if err.Error() != "illegal base64 data at input byte 4" {
t.Fatal("missing token value")
}
// Valid base64 value
_ = os.Setenv("GITHUB_ACCESS_TOKEN", "dGVzdC10b2tlbi12YWx1ZQ==")
err = loadConfiguration(mockKms)
if err != nil {
t.Fatal("error occurred", err.Error())
} else if len(config.GithubAccessToken) == 0 {
t.Fatal("missing token value")
} else if config.GithubAccessToken != "some-encrypted-text" {
t.Fatal("invalid token value", config.GithubAccessToken)
}
}