| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- package main
- import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/hex"
- "net/http/httptest"
- "strings"
- "testing"
- "time"
- )
- const secret = "test-secret"
- func sign(body string) string {
- mac := hmac.New(sha256.New, []byte(secret))
- mac.Write([]byte(body))
- return hex.EncodeToString(mac.Sum(nil))
- }
- type call struct{ repo, sha, by string }
- func TestHandler(t *testing.T) {
- merged := `{"action":"closed","pull_request":{"merged":true,"base_branch":"main","merge_commit_sha":"0bfb14ee4067"},"repository":{"full_name":"bajdev/posts"},"sender":{"username":"bajdev"}}`
- // Every release is of origin/main, whatever merge_commit_sha says: Gogs
- // puts the head branch's commit there, not the merge commit.
- withHead := call{"bajdev/posts", "origin/main", "PR merged by bajdev (head 0bfb14e)"}
- tests := []struct {
- name, method, event, body, sig string
- status int
- want *call // nil: no release
- }{
- {"merged into main", "POST", "pull_request", merged, "", 202, &withHead},
- {"no merge commit sha", "POST", "pull_request", strings.Replace(merged, `"0bfb14ee4067"`, `""`, 1), "", 202,
- &call{"bajdev/posts", "origin/main", "PR merged by bajdev"}},
- {"bad signature", "POST", "pull_request", merged, "deadbeef", 401, nil},
- {"missing signature", "POST", "pull_request", merged, "-", 401, nil},
- {"GET", "GET", "pull_request", merged, "", 405, nil},
- {"push event", "POST", "push", merged, "", 204, nil},
- {"opened", "POST", "pull_request", strings.Replace(merged, `"closed"`, `"opened"`, 1), "", 204, nil},
- {"closed without merge", "POST", "pull_request", strings.Replace(merged, `"merged":true`, `"merged":false`, 1), "", 204, nil},
- {"merged into another branch", "POST", "pull_request", strings.Replace(merged, `"main"`, `"dev"`, 1), "", 204, nil},
- {"no repository", "POST", "pull_request", strings.Replace(merged, `"bajdev/posts"`, `""`, 1), "", 204, nil},
- {"not JSON", "POST", "pull_request", "not json", "", 204, nil},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- calls := make(chan call, 1)
- h := handler([]byte(secret), func(repo, sha, by string) { calls <- call{repo, sha, by} })
- req := httptest.NewRequest(tt.method, "/deploy", strings.NewReader(tt.body))
- req.Header.Set("X-Gogs-Event", tt.event)
- switch tt.sig {
- case "":
- req.Header.Set("X-Gogs-Signature", sign(tt.body))
- case "-":
- default:
- req.Header.Set("X-Gogs-Signature", tt.sig)
- }
- rec := httptest.NewRecorder()
- h.ServeHTTP(rec, req)
- if rec.Code != tt.status {
- t.Fatalf("status = %d, want %d", rec.Code, tt.status)
- }
- select {
- case c := <-calls:
- if tt.want == nil {
- t.Fatalf("unexpected release %+v", c)
- }
- if c != *tt.want {
- t.Errorf("release called with %+v, want %+v", c, *tt.want)
- }
- case <-time.After(200 * time.Millisecond):
- if tt.want != nil {
- t.Fatal("release was not called")
- }
- }
- })
- }
- }
- func TestReleasesRunOneAtATime(t *testing.T) {
- body := `{"action":"closed","pull_request":{"merged":true,"base_branch":"main","merge_commit_sha":"x"},"repository":{"full_name":"a/b"}}`
- running, maxRunning := 0, 0
- done := make(chan struct{}, 3)
- h := handler([]byte(secret), func(repo, sha, by string) {
- // The handler's mutex is held here, so these updates don't race.
- running++
- if running > maxRunning {
- maxRunning = running
- }
- time.Sleep(20 * time.Millisecond)
- running--
- done <- struct{}{}
- })
- for i := 0; i < 3; i++ {
- req := httptest.NewRequest("POST", "/deploy", strings.NewReader(body))
- req.Header.Set("X-Gogs-Event", "pull_request")
- req.Header.Set("X-Gogs-Signature", sign(body))
- h.ServeHTTP(httptest.NewRecorder(), req)
- }
- for i := 0; i < 3; i++ {
- <-done
- }
- if maxRunning != 1 {
- t.Errorf("max concurrent releases = %d, want 1", maxRunning)
- }
- }
|