go-forge/admin_test.go

856 lines
24 KiB
Go
Raw Normal View History

package forge
import (
"context"
json "github.com/goccy/go-json"
"net/http"
"net/http/httptest"
"testing"
"dappco.re/go/core/forge/types"
)
func TestAdminService_ListUsers_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/users" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.User{
{ID: 1, UserName: "alice"},
{ID: 2, UserName: "bob"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
users, err := f.Admin.ListUsers(context.Background())
if err != nil {
t.Fatal(err)
}
if len(users) != 2 {
t.Errorf("got %d users, want 2", len(users))
}
if users[0].UserName != "alice" {
t.Errorf("got username=%q, want %q", users[0].UserName, "alice")
}
}
func TestAdminService_CreateUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/users" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateUserOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Username != "newuser" {
t.Errorf("got username=%q, want %q", opts.Username, "newuser")
}
if opts.Email != "new@example.com" {
t.Errorf("got email=%q, want %q", opts.Email, "new@example.com")
}
json.NewEncoder(w).Encode(types.User{ID: 42, UserName: "newuser", Email: "new@example.com"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
user, err := f.Admin.CreateUser(context.Background(), &types.CreateUserOption{
Username: "newuser",
Email: "new@example.com",
Password: "secret123",
})
if err != nil {
t.Fatal(err)
}
if user.ID != 42 {
t.Errorf("got id=%d, want 42", user.ID)
}
if user.UserName != "newuser" {
t.Errorf("got username=%q, want %q", user.UserName, "newuser")
}
}
func TestAdminService_DeleteUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/users/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.DeleteUser(context.Background(), "alice"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_RunCron_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/cron/repo_health_check" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.RunCron(context.Background(), "repo_health_check"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_EditUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/users/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body map[string]any
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body["email"] != "alice@new.com" {
t.Errorf("got email=%v, want %q", body["email"], "alice@new.com")
}
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
err := f.Admin.EditUser(context.Background(), "alice", map[string]any{
"email": "alice@new.com",
})
if err != nil {
t.Fatal(err)
}
}
func TestAdminService_RenameUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/users/alice/rename" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.RenameUserOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.NewName != "alice2" {
t.Errorf("got new_username=%q, want %q", opts.NewName, "alice2")
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.RenameUser(context.Background(), "alice", "alice2"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_ListOrgs_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/orgs" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Organization{
{ID: 10, Name: "myorg"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
orgs, err := f.Admin.ListOrgs(context.Background())
if err != nil {
t.Fatal(err)
}
if len(orgs) != 1 {
t.Errorf("got %d orgs, want 1", len(orgs))
}
if orgs[0].Name != "myorg" {
t.Errorf("got name=%q, want %q", orgs[0].Name, "myorg")
}
}
func TestAdminService_ListEmails_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/emails" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.Email{
{Email: "alice@example.com", Primary: true},
{Email: "bob@example.com", Verified: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
emails, err := f.Admin.ListEmails(context.Background())
if err != nil {
t.Fatal(err)
}
if len(emails) != 2 {
t.Errorf("got %d emails, want 2", len(emails))
}
if emails[0].Email != "alice@example.com" || !emails[0].Primary {
t.Errorf("got first email=%+v, want primary alice@example.com", emails[0])
}
}
func TestAdminService_ListHooks_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/hooks" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Hook{
{ID: 7, Type: "forgejo", URL: "https://example.com/admin-hook", Active: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
hooks, err := f.Admin.ListHooks(context.Background())
if err != nil {
t.Fatal(err)
}
if len(hooks) != 1 {
t.Fatalf("got %d hooks, want 1", len(hooks))
}
if hooks[0].ID != 7 || hooks[0].URL != "https://example.com/admin-hook" {
t.Errorf("unexpected hook: %+v", hooks[0])
}
}
func TestAdminService_CreateHook_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/hooks" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateHookOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Type != "forgejo" {
t.Errorf("got type=%q, want %q", opts.Type, "forgejo")
}
json.NewEncoder(w).Encode(types.Hook{
ID: 12,
Type: opts.Type,
Active: opts.Active,
Events: opts.Events,
URL: "https://example.com/admin-hook",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
hook, err := f.Admin.CreateHook(context.Background(), &types.CreateHookOption{
Type: "forgejo",
Active: true,
Events: []string{"push"},
})
if err != nil {
t.Fatal(err)
}
if hook.ID != 12 {
t.Errorf("got id=%d, want 12", hook.ID)
}
if hook.Type != "forgejo" {
t.Errorf("got type=%q, want %q", hook.Type, "forgejo")
}
}
func TestAdminService_GetHook_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/hooks/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.Hook{
ID: 7,
Type: "forgejo",
Active: true,
URL: "https://example.com/admin-hook",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
hook, err := f.Admin.GetHook(context.Background(), 7)
if err != nil {
t.Fatal(err)
}
if hook.ID != 7 {
t.Errorf("got id=%d, want 7", hook.ID)
}
}
func TestAdminService_EditHook_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/hooks/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.EditHookOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if !opts.Active {
t.Error("expected active=true")
}
json.NewEncoder(w).Encode(types.Hook{
ID: 7,
Type: "forgejo",
Active: opts.Active,
URL: "https://example.com/admin-hook",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
hook, err := f.Admin.EditHook(context.Background(), 7, &types.EditHookOption{Active: true})
if err != nil {
t.Fatal(err)
}
if hook.ID != 7 || !hook.Active {
t.Errorf("unexpected hook: %+v", hook)
}
}
func TestAdminService_DeleteHook_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/hooks/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.DeleteHook(context.Background(), 7); err != nil {
t.Fatal(err)
}
}
func TestAdminService_ListQuotaGroups_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode([]types.QuotaGroup{
{
Name: "default",
Rules: []*types.QuotaRuleInfo{
{Name: "git", Limit: 200000000, Subjects: []string{"size:repos:all"}},
},
},
{
Name: "premium",
},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
groups, err := f.Admin.ListQuotaGroups(context.Background())
if err != nil {
t.Fatal(err)
}
if len(groups) != 2 {
t.Fatalf("got %d groups, want 2", len(groups))
}
if groups[0].Name != "default" {
t.Errorf("got name=%q, want %q", groups[0].Name, "default")
}
if len(groups[0].Rules) != 1 || groups[0].Rules[0].Name != "git" {
t.Errorf("unexpected rules: %+v", groups[0].Rules)
}
}
func TestAdminService_CreateQuotaGroup_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateQuotaGroupOptions
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Name != "newgroup" {
t.Errorf("got name=%q, want %q", opts.Name, "newgroup")
}
if len(opts.Rules) != 1 || opts.Rules[0].Name != "git" {
t.Fatalf("unexpected rules: %+v", opts.Rules)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.QuotaGroup{
Name: opts.Name,
Rules: []*types.QuotaRuleInfo{
{
Name: opts.Rules[0].Name,
Limit: opts.Rules[0].Limit,
Subjects: opts.Rules[0].Subjects,
},
},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
group, err := f.Admin.CreateQuotaGroup(context.Background(), &types.CreateQuotaGroupOptions{
Name: "newgroup",
Rules: []*types.CreateQuotaRuleOptions{
{
Name: "git",
Limit: 200000000,
Subjects: []string{"size:repos:all"},
},
},
})
if err != nil {
t.Fatal(err)
}
if group.Name != "newgroup" {
t.Errorf("got name=%q, want %q", group.Name, "newgroup")
}
if len(group.Rules) != 1 || group.Rules[0].Limit != 200000000 {
t.Errorf("unexpected rules: %+v", group.Rules)
}
}
func TestAdminService_GetQuotaGroup_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups/default" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.QuotaGroup{
Name: "default",
Rules: []*types.QuotaRuleInfo{
{Name: "git", Limit: 200000000, Subjects: []string{"size:repos:all"}},
},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
group, err := f.Admin.GetQuotaGroup(context.Background(), "default")
if err != nil {
t.Fatal(err)
}
if group.Name != "default" {
t.Errorf("got name=%q, want %q", group.Name, "default")
}
if len(group.Rules) != 1 || group.Rules[0].Name != "git" {
t.Fatalf("unexpected rules: %+v", group.Rules)
}
}
func TestAdminService_DeleteQuotaGroup_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups/default" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.DeleteQuotaGroup(context.Background(), "default"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_ListQuotaGroupUsers_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups/default/users" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode([]types.User{
{ID: 1, UserName: "alice"},
{ID: 2, UserName: "bob"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
users, err := f.Admin.ListQuotaGroupUsers(context.Background(), "default")
if err != nil {
t.Fatal(err)
}
if len(users) != 2 {
t.Fatalf("got %d users, want 2", len(users))
}
if users[0].UserName != "alice" {
t.Errorf("got username=%q, want %q", users[0].UserName, "alice")
}
}
func TestAdminService_AddQuotaGroupUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPut {
t.Errorf("expected PUT, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups/default/users/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.AddQuotaGroupUser(context.Background(), "default", "alice"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_RemoveQuotaGroupUser_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/groups/default/users/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.RemoveQuotaGroupUser(context.Background(), "default", "alice"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_ListQuotaRules_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/rules" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.QuotaRuleInfo{
{Name: "git", Limit: 200000000, Subjects: []string{"size:repos:all"}},
{Name: "artifacts", Limit: 50000000, Subjects: []string{"size:assets:artifacts"}},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
rules, err := f.Admin.ListQuotaRules(context.Background())
if err != nil {
t.Fatal(err)
}
if len(rules) != 2 {
t.Fatalf("got %d rules, want 2", len(rules))
}
if rules[0].Name != "git" {
t.Errorf("got name=%q, want %q", rules[0].Name, "git")
}
}
func TestAdminService_CreateQuotaRule_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/rules" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateQuotaRuleOptions
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Name != "git" || opts.Limit != 200000000 {
t.Fatalf("unexpected options: %+v", opts)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.QuotaRuleInfo{
Name: opts.Name,
Limit: opts.Limit,
Subjects: opts.Subjects,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
rule, err := f.Admin.CreateQuotaRule(context.Background(), &types.CreateQuotaRuleOptions{
Name: "git",
Limit: 200000000,
Subjects: []string{"size:repos:all"},
})
if err != nil {
t.Fatal(err)
}
if rule.Name != "git" || rule.Limit != 200000000 {
t.Errorf("unexpected rule: %+v", rule)
}
}
func TestAdminService_GetQuotaRule_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/rules/git" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.QuotaRuleInfo{
Name: "git",
Limit: 200000000,
Subjects: []string{"size:repos:all"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
rule, err := f.Admin.GetQuotaRule(context.Background(), "git")
if err != nil {
t.Fatal(err)
}
if rule.Name != "git" {
t.Errorf("got name=%q, want %q", rule.Name, "git")
}
}
func TestAdminService_EditQuotaRule_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/rules/git" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.EditQuotaRuleOptions
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Limit != 500000000 {
t.Fatalf("unexpected options: %+v", opts)
}
json.NewEncoder(w).Encode(types.QuotaRuleInfo{
Name: "git",
Limit: opts.Limit,
Subjects: opts.Subjects,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
rule, err := f.Admin.EditQuotaRule(context.Background(), "git", &types.EditQuotaRuleOptions{
Limit: 500000000,
Subjects: []string{"size:repos:all", "size:assets:packages"},
})
if err != nil {
t.Fatal(err)
}
if rule.Limit != 500000000 {
t.Errorf("got limit=%d, want 500000000", rule.Limit)
}
}
func TestAdminService_DeleteQuotaRule_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/quota/rules/git" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.DeleteQuotaRule(context.Background(), "git"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_SearchEmails_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/emails/search" {
t.Errorf("wrong path: %s", r.URL.Path)
}
if got := r.URL.Query().Get("q"); got != "alice" {
t.Errorf("got q=%q, want %q", got, "alice")
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Email{
{Email: "alice@example.com", Primary: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
emails, err := f.Admin.SearchEmails(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(emails) != 1 {
t.Errorf("got %d emails, want 1", len(emails))
}
if emails[0].Email != "alice@example.com" {
t.Errorf("got email=%q, want %q", emails[0].Email, "alice@example.com")
}
}
func TestAdminService_ListCron_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/cron" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Cron{
{Name: "repo_health_check", Schedule: "@every 24h"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
crons, err := f.Admin.ListCron(context.Background())
if err != nil {
t.Fatal(err)
}
if len(crons) != 1 {
t.Errorf("got %d crons, want 1", len(crons))
}
if crons[0].Name != "repo_health_check" {
t.Errorf("got name=%q, want %q", crons[0].Name, "repo_health_check")
}
}
func TestAdminService_AdoptRepo_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/unadopted/alice/myrepo" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Admin.AdoptRepo(context.Background(), "alice", "myrepo"); err != nil {
t.Fatal(err)
}
}
func TestAdminService_GenerateRunnerToken_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/admin/runners/registration-token" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(map[string]string{"token": "abc123"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
token, err := f.Admin.GenerateRunnerToken(context.Background())
if err != nil {
t.Fatal(err)
}
if token != "abc123" {
t.Errorf("got token=%q, want %q", token, "abc123")
}
}
func TestAdminService_DeleteUser_NotFound_Bad(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"message": "user not found"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
err := f.Admin.DeleteUser(context.Background(), "nonexistent")
if !IsNotFound(err) {
t.Errorf("expected not found error, got %v", err)
}
}
func TestAdminService_CreateUser_Forbidden_Bad(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(map[string]string{"message": "only admins can create users"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
_, err := f.Admin.CreateUser(context.Background(), &types.CreateUserOption{
Username: "newuser",
Email: "new@example.com",
})
if !IsForbidden(err) {
t.Errorf("expected forbidden error, got %v", err)
}
}