github.com/go-playground/webhooks/v6@v6.3.0/gitlab/gitlab_test.go (about) 1 package gitlab 2 3 import ( 4 "bytes" 5 "io" 6 "log" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "reflect" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 // NOTES: 17 // - Run "go test" to run tests 18 // - Run "gocov test | gocov report" to report on test converage by file 19 // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called 20 // 21 // or 22 // 23 // -- may be a good idea to change to output path to somewherelike /tmp 24 // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html 25 // 26 27 const ( 28 path = "/webhooks" 29 ) 30 31 var hook *Webhook 32 33 func TestMain(m *testing.M) { 34 35 // setup 36 var err error 37 hook, err = New(Options.Secret("sampleToken!")) 38 if err != nil { 39 log.Fatal(err) 40 } 41 os.Exit(m.Run()) 42 43 // teardown 44 } 45 46 func newServer(handler http.HandlerFunc) *httptest.Server { 47 mux := http.NewServeMux() 48 mux.HandleFunc(path, handler) 49 return httptest.NewServer(mux) 50 } 51 52 func TestBadRequests(t *testing.T) { 53 assert := require.New(t) 54 tests := []struct { 55 name string 56 event Event 57 payload io.Reader 58 headers http.Header 59 }{ 60 { 61 name: "BadNoEventHeader", 62 event: PushEvents, 63 payload: bytes.NewBuffer([]byte("{}")), 64 headers: http.Header{}, 65 }, 66 { 67 name: "UnsubscribedEvent", 68 event: PushEvents, 69 payload: bytes.NewBuffer([]byte("{}")), 70 headers: http.Header{ 71 "X-Gitlab-Event": []string{"noneexistant_event"}, 72 }, 73 }, 74 { 75 name: "BadBody", 76 event: PushEvents, 77 payload: bytes.NewBuffer([]byte("")), 78 headers: http.Header{ 79 "X-Gitlab-Event": []string{"Push Hook"}, 80 "X-Gitlab-Token": []string{"sampleToken!"}, 81 }, 82 }, 83 { 84 name: "TokenMismatch", 85 event: PushEvents, 86 payload: bytes.NewBuffer([]byte("{}")), 87 headers: http.Header{ 88 "X-Gitlab-Event": []string{"Push Hook"}, 89 "X-Gitlab-Token": []string{"badsampleToken!!"}, 90 }, 91 }, 92 } 93 94 for _, tt := range tests { 95 tc := tt 96 client := &http.Client{} 97 t.Run(tt.name, func(t *testing.T) { 98 t.Parallel() 99 var parseError error 100 server := newServer(func(w http.ResponseWriter, r *http.Request) { 101 _, parseError = hook.Parse(r, tc.event) 102 }) 103 defer server.Close() 104 req, err := http.NewRequest(http.MethodPost, server.URL+path, tc.payload) 105 assert.NoError(err) 106 req.Header = tc.headers 107 req.Header.Set("Content-Type", "application/json") 108 109 resp, err := client.Do(req) 110 assert.NoError(err) 111 assert.Equal(http.StatusOK, resp.StatusCode) 112 assert.Error(parseError) 113 }) 114 } 115 } 116 117 func TestWebhooks(t *testing.T) { 118 assert := require.New(t) 119 tests := []struct { 120 name string 121 event Event 122 typ interface{} 123 filename string 124 headers http.Header 125 }{ 126 { 127 name: "PushEvent", 128 event: PushEvents, 129 typ: PushEventPayload{}, 130 filename: "../testdata/gitlab/push-event.json", 131 headers: http.Header{ 132 "X-Gitlab-Event": []string{"Push Hook"}, 133 }, 134 }, 135 { 136 name: "TagEvent", 137 event: TagEvents, 138 typ: TagEventPayload{}, 139 filename: "../testdata/gitlab/tag-event.json", 140 headers: http.Header{ 141 "X-Gitlab-Event": []string{"Tag Push Hook"}, 142 }, 143 }, 144 { 145 name: "IssueEvent", 146 event: IssuesEvents, 147 typ: IssueEventPayload{}, 148 filename: "../testdata/gitlab/issue-event.json", 149 headers: http.Header{ 150 "X-Gitlab-Event": []string{"Issue Hook"}, 151 }, 152 }, 153 { 154 name: "ConfidentialIssueEvent", 155 event: ConfidentialIssuesEvents, 156 typ: ConfidentialIssueEventPayload{}, 157 filename: "../testdata/gitlab/confidential-issue-event.json", 158 headers: http.Header{ 159 "X-Gitlab-Event": []string{"Confidential Issue Hook"}, 160 }, 161 }, 162 { 163 name: "CommentCommitEvent", 164 event: CommentEvents, 165 typ: CommentEventPayload{}, 166 filename: "../testdata/gitlab/comment-commit-event.json", 167 headers: http.Header{ 168 "X-Gitlab-Event": []string{"Note Hook"}, 169 }, 170 }, 171 { 172 name: "ConfidentialCommentCommitEvent", 173 event: ConfidentialCommentEvents, 174 typ: ConfidentialCommentEventPayload{}, 175 filename: "../testdata/gitlab/confidential-comment-event.json", 176 headers: http.Header{ 177 "X-Gitlab-Event": []string{"Confidential Note Hook"}, 178 }, 179 }, 180 { 181 name: "CommentMergeRequestEvent", 182 event: CommentEvents, 183 typ: CommentEventPayload{}, 184 filename: "../testdata/gitlab/comment-merge-request-event.json", 185 headers: http.Header{ 186 "X-Gitlab-Event": []string{"Note Hook"}, 187 }, 188 }, 189 { 190 name: "CommentIssueEvent", 191 event: CommentEvents, 192 typ: CommentEventPayload{}, 193 filename: "../testdata/gitlab/comment-issue-event.json", 194 headers: http.Header{ 195 "X-Gitlab-Event": []string{"Note Hook"}, 196 }, 197 }, 198 { 199 name: "CommentSnippetEvent", 200 event: CommentEvents, 201 typ: CommentEventPayload{}, 202 filename: "../testdata/gitlab/comment-snippet-event.json", 203 headers: http.Header{ 204 "X-Gitlab-Event": []string{"Note Hook"}, 205 }, 206 }, 207 { 208 name: "MergeRequestEvent", 209 event: MergeRequestEvents, 210 typ: MergeRequestEventPayload{}, 211 filename: "../testdata/gitlab/merge-request-event.json", 212 headers: http.Header{ 213 "X-Gitlab-Event": []string{"Merge Request Hook"}, 214 }, 215 }, 216 { 217 name: "WikipageEvent", 218 event: WikiPageEvents, 219 typ: WikiPageEventPayload{}, 220 filename: "../testdata/gitlab/wikipage-event.json", 221 headers: http.Header{ 222 "X-Gitlab-Event": []string{"Wiki Page Hook"}, 223 }, 224 }, 225 { 226 name: "PipelineEvent", 227 event: PipelineEvents, 228 typ: PipelineEventPayload{}, 229 filename: "../testdata/gitlab/pipeline-event.json", 230 headers: http.Header{ 231 "X-Gitlab-Event": []string{"Pipeline Hook"}, 232 }, 233 }, 234 { 235 name: "BuildEvent", 236 event: BuildEvents, 237 typ: BuildEventPayload{}, 238 filename: "../testdata/gitlab/build-event.json", 239 headers: http.Header{ 240 "X-Gitlab-Event": []string{"Build Hook"}, 241 }, 242 }, 243 { 244 name: "DeploymentEvent", 245 event: DeploymentEvents, 246 typ: DeploymentEventPayload{}, 247 filename: "../testdata/gitlab/deployment-event.json", 248 headers: http.Header{ 249 "X-Gitlab-Event": []string{"Deployment Hook"}, 250 }, 251 }, 252 } 253 254 for _, tt := range tests { 255 tc := tt 256 client := &http.Client{} 257 t.Run(tt.name, func(t *testing.T) { 258 t.Parallel() 259 payload, err := os.Open(tc.filename) 260 assert.NoError(err) 261 defer func() { 262 _ = payload.Close() 263 }() 264 265 var parseError error 266 var results interface{} 267 server := newServer(func(w http.ResponseWriter, r *http.Request) { 268 results, parseError = hook.Parse(r, tc.event) 269 }) 270 defer server.Close() 271 req, err := http.NewRequest(http.MethodPost, server.URL+path, payload) 272 assert.NoError(err) 273 req.Header = tc.headers 274 req.Header.Set("Content-Type", "application/json") 275 req.Header.Set("X-Gitlab-Token", "sampleToken!") 276 277 resp, err := client.Do(req) 278 assert.NoError(err) 279 assert.Equal(http.StatusOK, resp.StatusCode) 280 assert.NoError(parseError) 281 assert.Equal(reflect.TypeOf(tc.typ), reflect.TypeOf(results)) 282 }) 283 } 284 } 285 286 func TestJobHooks(t *testing.T) { 287 assert := require.New(t) 288 tests := []struct { 289 name string 290 events []Event 291 typ interface{} 292 filename string 293 headers http.Header 294 }{ 295 { 296 name: "JobEvent", 297 events: []Event{JobEvents, BuildEvents}, 298 typ: BuildEventPayload{}, 299 filename: "../testdata/gitlab/build-event.json", 300 headers: http.Header{ 301 "X-Gitlab-Event": []string{"Job Hook"}, 302 }, 303 }, 304 } 305 306 for _, tt := range tests { 307 tc := tt 308 client := &http.Client{} 309 t.Run(tt.name, func(t *testing.T) { 310 t.Parallel() 311 payload, err := os.Open(tc.filename) 312 assert.NoError(err) 313 defer func() { 314 _ = payload.Close() 315 }() 316 317 var parseError error 318 var results interface{} 319 server := newServer(func(w http.ResponseWriter, r *http.Request) { 320 results, parseError = hook.Parse(r, tc.events...) 321 }) 322 defer server.Close() 323 req, err := http.NewRequest(http.MethodPost, server.URL+path, payload) 324 assert.NoError(err) 325 req.Header = tc.headers 326 req.Header.Set("Content-Type", "application/json") 327 req.Header.Set("X-Gitlab-Token", "sampleToken!") 328 329 resp, err := client.Do(req) 330 assert.NoError(err) 331 assert.Equal(http.StatusOK, resp.StatusCode) 332 assert.NoError(parseError) 333 assert.Equal(reflect.TypeOf(tc.typ), reflect.TypeOf(results)) 334 }) 335 } 336 } 337 338 func TestSystemHooks(t *testing.T) { 339 assert := require.New(t) 340 tests := []struct { 341 name string 342 event Event 343 typ interface{} 344 filename string 345 }{ 346 { 347 name: "PushEvent", 348 event: PushEvents, 349 typ: PushEventPayload{}, 350 filename: "../testdata/gitlab/system-push-event.json", 351 }, 352 { 353 name: "TagEvent", 354 event: TagEvents, 355 typ: TagEventPayload{}, 356 filename: "../testdata/gitlab/system-tag-event.json", 357 }, 358 { 359 name: "MergeRequestEvent", 360 event: MergeRequestEvents, 361 typ: MergeRequestEventPayload{}, 362 filename: "../testdata/gitlab/system-merge-request-event.json", 363 }, 364 { 365 name: "ProjectCreatedEvent", 366 event: SystemHookEvents, 367 typ: ProjectCreatedEventPayload{}, 368 filename: "../testdata/gitlab/system-project-created.json", 369 }, 370 { 371 name: "ProjectDestroyedEvent", 372 event: SystemHookEvents, 373 typ: ProjectDestroyedEventPayload{}, 374 filename: "../testdata/gitlab/system-project-destroyed.json", 375 }, 376 { 377 name: "ProjectRenamedEvent", 378 event: SystemHookEvents, 379 typ: ProjectRenamedEventPayload{}, 380 filename: "../testdata/gitlab/system-project-renamed.json", 381 }, 382 { 383 name: "ProjectTransferredEvent", 384 event: SystemHookEvents, 385 typ: ProjectTransferredEventPayload{}, 386 filename: "../testdata/gitlab/system-project-transferred.json", 387 }, 388 { 389 name: "ProjectUpdatedEvent", 390 event: SystemHookEvents, 391 typ: ProjectUpdatedEventPayload{}, 392 filename: "../testdata/gitlab/system-project-updated.json", 393 }, 394 { 395 name: "TeamMemberAddedEvent", 396 event: SystemHookEvents, 397 typ: TeamMemberAddedEventPayload{}, 398 filename: "../testdata/gitlab/system-team-member-added.json", 399 }, 400 { 401 name: "TeamMemberRemovedEvent", 402 event: SystemHookEvents, 403 typ: TeamMemberRemovedEventPayload{}, 404 filename: "../testdata/gitlab/system-team-member-removed.json", 405 }, 406 { 407 name: "TeamMemberUpdatedEvent", 408 event: SystemHookEvents, 409 typ: TeamMemberUpdatedEventPayload{}, 410 filename: "../testdata/gitlab/system-team-member-updated.json", 411 }, 412 { 413 name: "UserCreatedEvent", 414 event: SystemHookEvents, 415 typ: UserCreatedEventPayload{}, 416 filename: "../testdata/gitlab/system-user-created.json", 417 }, 418 { 419 name: "UserRemovedEvent", 420 event: SystemHookEvents, 421 typ: UserRemovedEventPayload{}, 422 filename: "../testdata/gitlab/system-user-removed.json", 423 }, 424 { 425 name: "UserFailedLoginEvent", 426 event: SystemHookEvents, 427 typ: UserFailedLoginEventPayload{}, 428 filename: "../testdata/gitlab/system-user-failed-login.json", 429 }, 430 { 431 name: "UserRenamedEvent", 432 event: SystemHookEvents, 433 typ: UserRenamedEventPayload{}, 434 filename: "../testdata/gitlab/system-user-renamed.json", 435 }, 436 { 437 name: "KeyAddedEvent", 438 event: SystemHookEvents, 439 typ: KeyAddedEventPayload{}, 440 filename: "../testdata/gitlab/system-key-added.json", 441 }, 442 { 443 name: "KeyRemovedEvent", 444 event: SystemHookEvents, 445 typ: KeyRemovedEventPayload{}, 446 filename: "../testdata/gitlab/system-key-removed.json", 447 }, 448 { 449 name: "GroupCreatedEvent", 450 event: SystemHookEvents, 451 typ: GroupCreatedEventPayload{}, 452 filename: "../testdata/gitlab/system-group-created.json", 453 }, 454 { 455 name: "GroupRemovedEvent", 456 event: SystemHookEvents, 457 typ: GroupRemovedEventPayload{}, 458 filename: "../testdata/gitlab/system-group-removed.json", 459 }, 460 { 461 name: "GroupRenamedEvent", 462 event: SystemHookEvents, 463 typ: GroupRenamedEventPayload{}, 464 filename: "../testdata/gitlab/system-group-renamed.json", 465 }, 466 { 467 name: "GroupMemberAddedEvent", 468 event: SystemHookEvents, 469 typ: GroupMemberAddedEventPayload{}, 470 filename: "../testdata/gitlab/system-group-member-added.json", 471 }, 472 { 473 name: "GroupMemberRemovedEvent", 474 event: SystemHookEvents, 475 typ: GroupMemberRemovedEventPayload{}, 476 filename: "../testdata/gitlab/system-group-member-removed.json", 477 }, 478 { 479 name: "GroupMemberUpdatedEvent", 480 event: SystemHookEvents, 481 typ: GroupMemberUpdatedEventPayload{}, 482 filename: "../testdata/gitlab/system-group-member-updated.json", 483 }, 484 } 485 for _, tt := range tests { 486 tc := tt 487 client := &http.Client{} 488 t.Run(tt.name, func(t *testing.T) { 489 t.Parallel() 490 payload, err := os.Open(tc.filename) 491 assert.NoError(err) 492 defer func() { 493 _ = payload.Close() 494 }() 495 496 var parseError error 497 var results interface{} 498 server := newServer(func(w http.ResponseWriter, r *http.Request) { 499 results, parseError = hook.Parse(r, SystemHookEvents, tc.event) 500 }) 501 defer server.Close() 502 req, err := http.NewRequest(http.MethodPost, server.URL+path, payload) 503 assert.NoError(err) 504 req.Header.Set("Content-Type", "application/json") 505 req.Header.Set("X-Gitlab-Token", "sampleToken!") 506 req.Header.Set("X-Gitlab-Event", "System Hook") 507 508 resp, err := client.Do(req) 509 assert.NoError(err) 510 assert.Equal(http.StatusOK, resp.StatusCode) 511 assert.NoError(parseError) 512 assert.Equal(reflect.TypeOf(tc.typ), reflect.TypeOf(results)) 513 }) 514 } 515 }