f1bcb8cd3a
repospawner turns JSON new-repo requests into terraform-git pull requests via kubernetes Jobs, follows those PRs to merge and optionally activates the repository in Woodpecker.
185 lines
5.6 KiB
Go
185 lines
5.6 KiB
Go
package gitea
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
func staticToken(tok string) TokenFunc {
|
|
return func(context.Context, bool) (string, error) { return tok, nil }
|
|
}
|
|
|
|
func TestFileExists(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
status int
|
|
want bool
|
|
errors bool
|
|
}{
|
|
{name: "present", status: http.StatusOK, want: true},
|
|
{name: "absent", status: http.StatusNotFound, want: false},
|
|
{name: "forge broken", status: http.StatusInternalServerError, errors: true},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var gotPath, gotAuth string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath, gotAuth = r.URL.Path, r.Header.Get("Authorization")
|
|
w.WriteHeader(tc.status)
|
|
_, _ = w.Write([]byte(`{}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := New(srv.URL, staticToken("tok"))
|
|
got, err := c.FileExists(context.Background(), "unkin/terraform-git",
|
|
"config/git.unkin.net/unkin/repository/widget.yaml", "main")
|
|
if tc.errors {
|
|
if err == nil {
|
|
t.Fatal("expected an error for a broken forge, got nil")
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("FileExists: %v", err)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("FileExists = %v, want %v", got, tc.want)
|
|
}
|
|
wantPath := "/api/v1/repos/unkin/terraform-git/contents/config/git.unkin.net/unkin/repository/widget.yaml"
|
|
if gotPath != wantPath {
|
|
t.Errorf("path = %q, want %q", gotPath, wantPath)
|
|
}
|
|
if gotAuth != "token tok" {
|
|
t.Errorf("Authorization = %q", gotAuth)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreatePullRequest(t *testing.T) {
|
|
var body map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost || r.URL.Path != "/api/v1/repos/unkin/terraform-git/pulls" {
|
|
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
|
|
}
|
|
raw, _ := io.ReadAll(r.Body)
|
|
_ = json.Unmarshal(raw, &body)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"number":42,"html_url":"https://git.unkin.net/unkin/terraform-git/pulls/42","state":"open"}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
pr, err := New(srv.URL, staticToken("tok")).CreatePullRequest(
|
|
context.Background(), "unkin/terraform-git", "repospawner/widget", "main", "Add widget", "why")
|
|
if err != nil {
|
|
t.Fatalf("CreatePullRequest: %v", err)
|
|
}
|
|
if pr.Number != 42 || !strings.HasSuffix(pr.HTMLURL, "/42") {
|
|
t.Errorf("pr = %+v", pr)
|
|
}
|
|
if body["head"] != "repospawner/widget" || body["base"] != "main" || body["title"] != "Add widget" {
|
|
t.Errorf("payload = %v", body)
|
|
}
|
|
}
|
|
|
|
func TestCreateFileBase64EncodesContent(t *testing.T) {
|
|
var body map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
raw, _ := io.ReadAll(r.Body)
|
|
_ = json.Unmarshal(raw, &body)
|
|
_, _ = w.Write([]byte(`{}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
err := New(srv.URL, staticToken("tok")).CreateFile(context.Background(),
|
|
"unkin/terraform-git", "config/a/b.yaml", "repospawner/widget", "Add widget", []byte("description: x\n"))
|
|
if err != nil {
|
|
t.Fatalf("CreateFile: %v", err)
|
|
}
|
|
decoded, err := base64.StdEncoding.DecodeString(body["content"])
|
|
if err != nil {
|
|
t.Fatalf("content is not base64: %v", err)
|
|
}
|
|
if string(decoded) != "description: x\n" {
|
|
t.Errorf("content = %q", decoded)
|
|
}
|
|
if body["branch"] != "repospawner/widget" {
|
|
t.Errorf("branch = %q", body["branch"])
|
|
}
|
|
}
|
|
|
|
func TestCreateBranchToleratesExisting(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusConflict)
|
|
_, _ = w.Write([]byte(`{"message":"branch already exists"}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
if err := New(srv.URL, staticToken("tok")).CreateBranch(context.Background(),
|
|
"unkin/terraform-git", "repospawner/widget", "main"); err != nil {
|
|
t.Fatalf("CreateBranch on an existing branch should succeed, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestReMintsTokenOn401(t *testing.T) {
|
|
var mints atomic.Int32
|
|
token := func(_ context.Context, force bool) (string, error) {
|
|
if force {
|
|
mints.Add(1)
|
|
return "fresh", nil
|
|
}
|
|
return "stale", nil
|
|
}
|
|
|
|
var seen []string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
auth := r.Header.Get("Authorization")
|
|
seen = append(seen, auth)
|
|
if auth == "token stale" {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
_, _ = w.Write([]byte(`{"message":"token expired"}`))
|
|
return
|
|
}
|
|
_, _ = w.Write([]byte(`{"number":7,"html_url":"https://example/7","state":"open","merged":true}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
pr, err := New(srv.URL, token).PullRequest(context.Background(), "unkin/terraform-git", 7)
|
|
if err != nil {
|
|
t.Fatalf("PullRequest: %v", err)
|
|
}
|
|
if !pr.Merged || pr.Number != 7 {
|
|
t.Errorf("pr = %+v", pr)
|
|
}
|
|
if mints.Load() != 1 {
|
|
t.Errorf("forced mints = %d, want 1", mints.Load())
|
|
}
|
|
if len(seen) != 2 || seen[0] != "token stale" || seen[1] != "token fresh" {
|
|
t.Errorf("authorization headers = %v", seen)
|
|
}
|
|
}
|
|
|
|
func TestStatusErrorCarriesBody(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
_, _ = w.Write([]byte(`{"message":"branch already has a pull request"}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
_, err := New(srv.URL, staticToken("tok")).CreatePullRequest(
|
|
context.Background(), "unkin/terraform-git", "h", "main", "t", "b")
|
|
if err == nil {
|
|
t.Fatal("expected an error")
|
|
}
|
|
if !strings.Contains(err.Error(), "422") || !strings.Contains(err.Error(), "already has a pull request") {
|
|
t.Errorf("error = %v", err)
|
|
}
|
|
}
|