Files
lvmh/daemon/gitlab_test.go

123 lines
3.5 KiB
Go

package main
// gitlab_test.go — token connect + repo mapping against httptest upstream (Gitea v1).
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func newGitLabUpstream(t *testing.T) (*httptest.Server, *GitLab) {
t.Helper()
mux := http.NewServeMux()
mux.HandleFunc("/api/v1/user", func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "token pat-good" {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"login":"alice"}`))
})
mux.HandleFunc("/api/v1/user/repos", func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "token pat-good" {
w.WriteHeader(http.StatusUnauthorized)
return
}
if r.URL.Query().Get("limit") == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[
{"full_name":"team/b","name":"B","owner":{"login":"team"},
"updated_at":"2024-02-02T00:00:00Z","html_url":"https://gl/team/b","default_branch":"main"},
{"full_name":"team/a","name":"A","owner":{"login":"team"},
"updated_at":"2024-03-03T00:00:00Z","html_url":"https://gl/team/a","default_branch":"trunk"}
]`))
})
ts := httptest.NewServer(mux)
t.Cleanup(ts.Close)
store := openTestStore(t)
return ts, NewGitLab(store, ts.URL)
}
func TestGitLabConnectValidatesAndStores(t *testing.T) {
_, gl := newGitLabUpstream(t)
if status := gl.Status(); status["connected"] != false {
t.Fatalf("status before connect = %v", status)
}
if _, err := gl.Connect(context.Background(), "pat-bad"); err == nil {
t.Fatal("bad PAT should fail validation")
}
username, err := gl.Connect(context.Background(), "pat-good")
if err != nil {
t.Fatalf("connect: %v", err)
}
if username != "alice" {
t.Fatalf("username = %q", username)
}
status := gl.Status()
if status["connected"] != true || status["username"] != "alice" {
t.Fatalf("status after connect = %v", status)
}
if strings.Contains(mustJSON(t, status), "pat-good") {
t.Fatal("status must never expose the PAT")
}
if err := gl.Disconnect(); err != nil {
t.Fatalf("disconnect: %v", err)
}
if status := gl.Status(); status["connected"] != false {
t.Fatalf("status after disconnect = %v", status)
}
}
func mustJSON(t *testing.T, v any) string {
t.Helper()
b, err := json.Marshal(v)
if err != nil {
t.Fatalf("marshal: %v", err)
}
return string(b)
}
func TestGitLabReposMappingAndSorting(t *testing.T) {
_, gl := newGitLabUpstream(t)
if _, err := gl.Repos(context.Background()); err == nil || !strings.Contains(err.Error(), "not connected") {
t.Fatalf("repos without connect = %v, want not-connected error", err)
}
if _, err := gl.Connect(context.Background(), "pat-good"); err != nil {
t.Fatalf("connect: %v", err)
}
repos, err := gl.Repos(context.Background())
if err != nil {
t.Fatalf("repos: %v", err)
}
if len(repos) != 2 {
t.Fatalf("repos = %d, want 2", len(repos))
}
want := GitLabRepo{
Path: "team/a", Name: "A", Namespace: "team",
LastActivityAt: "2024-03-03T00:00:00Z", WebURL: "https://gl/team/a", DefaultBranch: "trunk",
}
if repos[0] != want {
t.Fatalf("first repo = %+v, want %+v (sorted by activity desc)", repos[0], want)
}
encoded := mustJSON(t, repos[0])
for _, key := range []string{`"path":"team/a"`, `"namespace":"team"`, `"webUrl":"https://gl/team/a"`, `"defaultBranch":"trunk"`} {
if !strings.Contains(encoded, key) {
t.Fatalf("repo JSON %s missing %s", encoded, key)
}
}
}