go-forge/users_test.go
Virgil 1a8fdf53ef
Some checks failed
Security Scan / security (push) Successful in 13s
Test / test (push) Has been cancelled
feat(users): add access token and user key endpoints
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 06:02:22 +00:00

1691 lines
48 KiB
Go

package forge
import (
"context"
json "github.com/goccy/go-json"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"dappco.re/go/core/forge/types"
)
func TestUserService_Get_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/users/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.User{ID: 1, UserName: "alice"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
user, err := f.Users.Get(context.Background(), Params{"username": "alice"})
if err != nil {
t.Fatal(err)
}
if user.UserName != "alice" {
t.Errorf("got username=%q, want %q", user.UserName, "alice")
}
}
func TestUserService_GetCurrent_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/user" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.User{ID: 1, UserName: "me"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
user, err := f.Users.GetCurrent(context.Background())
if err != nil {
t.Fatal(err)
}
if user.UserName != "me" {
t.Errorf("got username=%q, want %q", user.UserName, "me")
}
}
func TestUserService_GetSettings_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/user/settings" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.UserSettings{
FullName: "Alice",
Language: "en-US",
Theme: "forgejo-auto",
HideEmail: true,
Pronouns: "she/her",
Website: "https://example.com",
Location: "Earth",
Description: "maintainer",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
settings, err := f.Users.GetSettings(context.Background())
if err != nil {
t.Fatal(err)
}
if settings.FullName != "Alice" {
t.Errorf("got full name=%q, want %q", settings.FullName, "Alice")
}
if !settings.HideEmail {
t.Errorf("got hide_email=%v, want true", settings.HideEmail)
}
}
func TestUserService_UpdateSettings_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/user/settings" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.UserSettingsOptions
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.FullName != "Alice" || !body.HideEmail || body.Theme != "forgejo-auto" {
t.Fatalf("unexpected body: %+v", body)
}
json.NewEncoder(w).Encode(types.UserSettings{
FullName: body.FullName,
HideEmail: body.HideEmail,
Theme: body.Theme,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
settings, err := f.Users.UpdateSettings(context.Background(), &types.UserSettingsOptions{
FullName: "Alice",
HideEmail: true,
Theme: "forgejo-auto",
})
if err != nil {
t.Fatal(err)
}
if settings.FullName != "Alice" {
t.Errorf("got full name=%q, want %q", settings.FullName, "Alice")
}
if !settings.HideEmail {
t.Errorf("got hide_email=%v, want true", settings.HideEmail)
}
}
func TestUserService_GetQuota_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/user/quota" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.QuotaInfo{
Groups: &types.QuotaGroupList{},
Used: &types.QuotaUsed{
Size: &types.QuotaUsedSize{
Repos: &types.QuotaUsedSizeRepos{
Public: 123,
Private: 456,
},
},
},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
quota, err := f.Users.GetQuota(context.Background())
if err != nil {
t.Fatal(err)
}
if quota.Used == nil || quota.Used.Size == nil || quota.Used.Size.Repos == nil {
t.Fatalf("quota usage was not decoded: %+v", quota)
}
if quota.Used.Size.Repos.Public != 123 || quota.Used.Size.Repos.Private != 456 {
t.Errorf("unexpected repository quota usage: %+v", quota.Used.Size.Repos)
}
}
func TestUserService_SearchUsersPage_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/users/search" {
t.Errorf("wrong path: %s", r.URL.Path)
http.NotFound(w, r)
return
}
if got := r.URL.Query().Get("q"); got != "al" {
t.Errorf("wrong q: %s", got)
}
if got := r.URL.Query().Get("uid"); got != "7" {
t.Errorf("wrong uid: %s", got)
}
if got := r.URL.Query().Get("page"); got != "1" {
t.Errorf("wrong page: %s", got)
}
if got := r.URL.Query().Get("limit"); got != "50" {
t.Errorf("wrong limit: %s", got)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode(map[string]any{
"data": []*types.User{
{ID: 1, UserName: "alice"},
{ID: 2, UserName: "alex"},
},
"ok": true,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
result, err := f.Users.SearchUsersPage(context.Background(), "al", ListOptions{}, UserSearchOptions{UID: 7})
if err != nil {
t.Fatal(err)
}
if result.TotalCount != 2 || result.Page != 1 || result.HasMore {
t.Fatalf("got %#v", result)
}
if len(result.Items) != 2 || result.Items[0].UserName != "alice" || result.Items[1].UserName != "alex" {
t.Fatalf("got %#v", result.Items)
}
}
func TestUserService_SearchUsers_Good(t *testing.T) {
var requests int
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requests++
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/users/search" {
t.Errorf("wrong path: %s", r.URL.Path)
http.NotFound(w, r)
return
}
if got := r.URL.Query().Get("q"); got != "al" {
t.Errorf("wrong q: %s", got)
}
if got := r.URL.Query().Get("limit"); got != strconv.Itoa(50) {
t.Errorf("wrong limit: %s", got)
}
switch r.URL.Query().Get("page") {
case "1":
w.Header().Set("X-Total-Count", "3")
json.NewEncoder(w).Encode(map[string]any{
"data": []*types.User{
{ID: 1, UserName: "alice"},
{ID: 2, UserName: "alex"},
},
"ok": true,
})
case "2":
w.Header().Set("X-Total-Count", "3")
json.NewEncoder(w).Encode(map[string]any{
"data": []*types.User{
{ID: 3, UserName: "ally"},
},
"ok": true,
})
default:
t.Fatalf("unexpected page %q", r.URL.Query().Get("page"))
}
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
var got []string
for user, err := range f.Users.IterSearchUsers(context.Background(), "al") {
if err != nil {
t.Fatal(err)
}
got = append(got, user.UserName)
}
if requests != 2 {
t.Fatalf("expected 2 requests, got %d", requests)
}
if len(got) != 3 || got[0] != "alice" || got[1] != "alex" || got[2] != "ally" {
t.Fatalf("got %#v", got)
}
}
func TestUserService_ListQuotaArtifacts_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/user/quota/artifacts" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.QuotaUsedArtifact{
{Name: "artifact-1", Size: 123, HTMLURL: "https://example.com/actions/runs/1"},
{Name: "artifact-2", Size: 456, HTMLURL: "https://example.com/actions/runs/2"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
artifacts, err := f.Users.ListQuotaArtifacts(context.Background())
if err != nil {
t.Fatal(err)
}
if len(artifacts) != 2 {
t.Fatalf("got %d artifacts, want 2", len(artifacts))
}
if artifacts[0].Name != "artifact-1" || artifacts[0].Size != 123 {
t.Errorf("unexpected first artifact: %+v", artifacts[0])
}
}
func TestUserService_IterQuotaArtifacts_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/user/quota/artifacts" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.QuotaUsedArtifact{
{Name: "artifact-1", Size: 123, HTMLURL: "https://example.com/actions/runs/1"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
var got []types.QuotaUsedArtifact
for artifact, err := range f.Users.IterQuotaArtifacts(context.Background()) {
if err != nil {
t.Fatal(err)
}
got = append(got, artifact)
}
if len(got) != 1 {
t.Fatalf("got %d artifacts, want 1", len(got))
}
if got[0].Name != "artifact-1" {
t.Errorf("unexpected artifact: %+v", got[0])
}
}
func TestUserService_ListQuotaAttachments_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/user/quota/attachments" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.QuotaUsedAttachment{
{Name: "issue-attachment.png", Size: 123, APIURL: "https://example.com/api/attachments/1"},
{Name: "release-attachment.tar.gz", Size: 456, APIURL: "https://example.com/api/attachments/2"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
attachments, err := f.Users.ListQuotaAttachments(context.Background())
if err != nil {
t.Fatal(err)
}
if len(attachments) != 2 {
t.Fatalf("got %d attachments, want 2", len(attachments))
}
if attachments[0].Name != "issue-attachment.png" || attachments[0].Size != 123 {
t.Errorf("unexpected first attachment: %+v", attachments[0])
}
}
func TestUserService_IterQuotaAttachments_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/user/quota/attachments" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.QuotaUsedAttachment{
{Name: "issue-attachment.png", Size: 123, APIURL: "https://example.com/api/attachments/1"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
var got []types.QuotaUsedAttachment
for attachment, err := range f.Users.IterQuotaAttachments(context.Background()) {
if err != nil {
t.Fatal(err)
}
got = append(got, attachment)
}
if len(got) != 1 {
t.Fatalf("got %d attachments, want 1", len(got))
}
if got[0].Name != "issue-attachment.png" {
t.Errorf("unexpected attachment: %+v", got[0])
}
}
func TestUserService_ListQuotaPackages_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/user/quota/packages" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.QuotaUsedPackage{
{Name: "pkg-one", Type: "container", Version: "1.0.0", Size: 123, HTMLURL: "https://example.com/packages/1"},
{Name: "pkg-two", Type: "npm", Version: "2.0.0", Size: 456, HTMLURL: "https://example.com/packages/2"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
packages, err := f.Users.ListQuotaPackages(context.Background())
if err != nil {
t.Fatal(err)
}
if len(packages) != 2 {
t.Fatalf("got %d packages, want 2", len(packages))
}
if packages[0].Name != "pkg-one" || packages[0].Type != "container" || packages[0].Size != 123 {
t.Errorf("unexpected first package: %+v", packages[0])
}
}
func TestUserService_IterQuotaPackages_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/user/quota/packages" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.QuotaUsedPackage{
{Name: "pkg-one", Type: "container", Version: "1.0.0", Size: 123, HTMLURL: "https://example.com/packages/1"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
var got []types.QuotaUsedPackage
for pkg, err := range f.Users.IterQuotaPackages(context.Background()) {
if err != nil {
t.Fatal(err)
}
got = append(got, pkg)
}
if len(got) != 1 {
t.Fatalf("got %d packages, want 1", len(got))
}
if got[0].Name != "pkg-one" || got[0].Type != "container" {
t.Errorf("unexpected package: %+v", got[0])
}
}
func TestUserService_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/user/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: "alice+alt@example.com", Verified: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
emails, err := f.Users.ListEmails(context.Background())
if err != nil {
t.Fatal(err)
}
if len(emails) != 2 {
t.Fatalf("got %d emails, want 2", len(emails))
}
if emails[0].Email != "alice@example.com" || !emails[0].Primary {
t.Errorf("unexpected first email: %+v", emails[0])
}
}
func TestUserService_ListStopwatches_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/user/stopwatches" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.StopWatch{
{IssueIndex: 12, IssueTitle: "First issue", RepoOwnerName: "core", RepoName: "go-forge", Seconds: 30},
{IssueIndex: 13, IssueTitle: "Second issue", RepoOwnerName: "core", RepoName: "go-forge", Seconds: 90},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
stopwatches, err := f.Users.ListStopwatches(context.Background())
if err != nil {
t.Fatal(err)
}
if len(stopwatches) != 2 {
t.Fatalf("got %d stopwatches, want 2", len(stopwatches))
}
if stopwatches[0].IssueIndex != 12 || stopwatches[0].Seconds != 30 {
t.Errorf("unexpected first stopwatch: %+v", stopwatches[0])
}
}
func TestUserService_ListBlockedUsers_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/user/list_blocked" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.BlockedUser{
{BlockID: 11},
{BlockID: 12},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
blocked, err := f.Users.ListBlockedUsers(context.Background())
if err != nil {
t.Fatal(err)
}
if len(blocked) != 2 {
t.Fatalf("got %d blocked users, want 2", len(blocked))
}
if blocked[0].BlockID != 11 {
t.Errorf("unexpected first blocked user: %+v", blocked[0])
}
}
func TestUserService_Block_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/user/block/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.Block(context.Background(), "alice"); err != nil {
t.Fatal(err)
}
}
func TestUserService_CheckFollowing_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/users/alice/following/bob" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
following, err := f.Users.CheckFollowing(context.Background(), "alice", "bob")
if err != nil {
t.Fatal(err)
}
if !following {
t.Fatal("got following=false, want true")
}
}
func TestUserService_CheckFollowing_Bad_NotFound(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/users/alice/following/bob" {
t.Errorf("wrong path: %s", r.URL.Path)
}
http.Error(w, "not found", http.StatusNotFound)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
following, err := f.Users.CheckFollowing(context.Background(), "alice", "bob")
if err != nil {
t.Fatal(err)
}
if following {
t.Fatal("got following=true, want false")
}
}
func TestUserService_Unblock_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/user/unblock/alice" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.Unblock(context.Background(), "alice"); err != nil {
t.Fatal(err)
}
}
func TestUserService_IterBlockedUsers_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/user/list_blocked" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.BlockedUser{
{BlockID: 77},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for blocked, err := range f.Users.IterBlockedUsers(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if blocked.BlockID != 77 {
t.Errorf("unexpected blocked user: %+v", blocked)
}
}
if count != 1 {
t.Fatalf("got %d blocked users, want 1", count)
}
}
func TestUserService_ListMySubscriptions_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/user/subscriptions" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
repos, err := f.Users.ListMySubscriptions(context.Background())
if err != nil {
t.Fatal(err)
}
if len(repos) != 1 {
t.Fatalf("got %d repositories, want 1", len(repos))
}
if repos[0].FullName != "core/go-forge" {
t.Errorf("got full name=%q, want %q", repos[0].FullName, "core/go-forge")
}
}
func TestUserService_IterMySubscriptions_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/user/subscriptions" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for repo, err := range f.Users.IterMySubscriptions(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if repo.FullName != "core/go-forge" {
t.Errorf("got full name=%q, want %q", repo.FullName, "core/go-forge")
}
}
if count != 1 {
t.Fatalf("got %d repositories, want 1", count)
}
}
func TestUserService_IterStopwatches_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/user/stopwatches" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.StopWatch{
{IssueIndex: 99, IssueTitle: "Running task", RepoOwnerName: "core", RepoName: "go-forge", Seconds: 300},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for sw, err := range f.Users.IterStopwatches(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if sw.IssueIndex != 99 || sw.Seconds != 300 {
t.Errorf("unexpected stopwatch: %+v", sw)
}
}
if count != 1 {
t.Fatalf("got %d stopwatches, want 1", count)
}
}
func TestUserService_AddEmails_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/user/emails" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateEmailOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if len(body.Emails) != 2 || body.Emails[0] != "alice@example.com" || body.Emails[1] != "alice+alt@example.com" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode([]types.Email{
{Email: "alice@example.com", Primary: true},
{Email: "alice+alt@example.com", Verified: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
emails, err := f.Users.AddEmails(context.Background(), "alice@example.com", "alice+alt@example.com")
if err != nil {
t.Fatal(err)
}
if len(emails) != 2 {
t.Fatalf("got %d emails, want 2", len(emails))
}
if emails[1].Email != "alice+alt@example.com" || !emails[1].Verified {
t.Errorf("unexpected second email: %+v", emails[1])
}
}
func TestUserService_DeleteEmails_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/user/emails" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.DeleteEmailOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if len(body.Emails) != 1 || body.Emails[0] != "alice+alt@example.com" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteEmails(context.Background(), "alice+alt@example.com"); err != nil {
t.Fatal(err)
}
}
func TestUserService_UpdateAvatar_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/user/avatar" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.UpdateUserAvatarOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.Image != "aGVsbG8=" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.UpdateAvatar(context.Background(), &types.UpdateUserAvatarOption{Image: "aGVsbG8="}); err != nil {
t.Fatal(err)
}
}
func TestUserService_DeleteAvatar_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/user/avatar" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteAvatar(context.Background()); err != nil {
t.Fatal(err)
}
}
func TestUserService_ListKeysWithFilters_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/user/keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
if got := r.URL.Query().Get("fingerprint"); got != "ABCD1234" {
t.Fatalf("unexpected fingerprint query: %q", got)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.PublicKey{
{ID: 1, Title: "laptop", ReadOnly: true},
{ID: 2, Title: "desktop", ReadOnly: false},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
keys, err := f.Users.ListKeys(context.Background(), UserKeyListOptions{
Fingerprint: "ABCD1234",
})
if err != nil {
t.Fatal(err)
}
if len(keys) != 2 {
t.Fatalf("got %d keys, want 2", len(keys))
}
if keys[0].ID != 1 || keys[0].Title != "laptop" || !keys[0].ReadOnly {
t.Errorf("unexpected first key: %+v", keys[0])
}
}
func TestUserService_IterKeys_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/user/keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.PublicKey{
{ID: 3, Title: "workstation", KeyType: "ssh-ed25519"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for key, err := range f.Users.IterKeys(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if key.ID != 3 || key.Title != "workstation" || key.KeyType != "ssh-ed25519" {
t.Errorf("unexpected key: %+v", key)
}
}
if count != 1 {
t.Fatalf("got %d keys, want 1", count)
}
}
func TestUserService_CreateKey_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/user/keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateKeyOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.Key != "ssh-ed25519 AAAAC3Nza..." || body.Title != "laptop" || !body.ReadOnly {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.PublicKey{
ID: 9,
Title: "laptop",
KeyType: "ssh-ed25519",
ReadOnly: true,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
key, err := f.Users.CreateKey(context.Background(), &types.CreateKeyOption{
Key: "ssh-ed25519 AAAAC3Nza...",
Title: "laptop",
ReadOnly: true,
})
if err != nil {
t.Fatal(err)
}
if key.ID != 9 || key.Title != "laptop" || key.KeyType != "ssh-ed25519" || !key.ReadOnly {
t.Errorf("unexpected key: %+v", key)
}
}
func TestUserService_GetKey_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/user/keys/9" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.PublicKey{
ID: 9,
Title: "laptop",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
key, err := f.Users.GetKey(context.Background(), 9)
if err != nil {
t.Fatal(err)
}
if key.ID != 9 || key.Title != "laptop" {
t.Errorf("unexpected key: %+v", key)
}
}
func TestUserService_DeleteKey_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/user/keys/9" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteKey(context.Background(), 9); err != nil {
t.Fatal(err)
}
}
func TestUserService_ListGPGKeys_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/user/gpg_keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.GPGKey{
{ID: 1, KeyID: "ABCD1234", PublicKey: "-----BEGIN PGP PUBLIC KEY BLOCK-----"},
{ID: 2, KeyID: "EFGH5678", Verified: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
keys, err := f.Users.ListGPGKeys(context.Background())
if err != nil {
t.Fatal(err)
}
if len(keys) != 2 {
t.Fatalf("got %d keys, want 2", len(keys))
}
if keys[0].ID != 1 || keys[0].KeyID != "ABCD1234" {
t.Errorf("unexpected first key: %+v", keys[0])
}
}
func TestUserService_IterGPGKeys_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/user/gpg_keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.GPGKey{
{ID: 3, KeyID: "IJKL9012", Verified: true},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for key, err := range f.Users.IterGPGKeys(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if key.ID != 3 || key.KeyID != "IJKL9012" {
t.Errorf("unexpected key: %+v", key)
}
}
if count != 1 {
t.Fatalf("got %d keys, want 1", count)
}
}
func TestUserService_CreateGPGKey_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/user/gpg_keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateGPGKeyOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.ArmoredKey != "-----BEGIN PGP PUBLIC KEY BLOCK-----" || body.Signature != "sig" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.GPGKey{
ID: 9,
KeyID: "MNOP3456",
Verified: true,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
key, err := f.Users.CreateGPGKey(context.Background(), &types.CreateGPGKeyOption{
ArmoredKey: "-----BEGIN PGP PUBLIC KEY BLOCK-----",
Signature: "sig",
})
if err != nil {
t.Fatal(err)
}
if key.ID != 9 || key.KeyID != "MNOP3456" || !key.Verified {
t.Errorf("unexpected key: %+v", key)
}
}
func TestUserService_GetGPGKey_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/user/gpg_keys/9" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.GPGKey{
ID: 9,
KeyID: "MNOP3456",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
key, err := f.Users.GetGPGKey(context.Background(), 9)
if err != nil {
t.Fatal(err)
}
if key.ID != 9 || key.KeyID != "MNOP3456" {
t.Errorf("unexpected key: %+v", key)
}
}
func TestUserService_DeleteGPGKey_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/user/gpg_keys/9" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteGPGKey(context.Background(), 9); err != nil {
t.Fatal(err)
}
}
func TestUserService_GetGPGKeyVerificationToken_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/user/gpg_key_token" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Write([]byte("verification-token"))
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
token, err := f.Users.GetGPGKeyVerificationToken(context.Background())
if err != nil {
t.Fatal(err)
}
if token != "verification-token" {
t.Errorf("got token=%q, want %q", token, "verification-token")
}
}
func TestUserService_VerifyGPGKey_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/user/gpg_key_verify" {
t.Errorf("wrong path: %s", r.URL.Path)
}
if got := r.Header.Get("Content-Type"); got != "" {
t.Errorf("unexpected content type: %q", got)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.GPGKey{
ID: 12,
KeyID: "QRST7890",
Verified: true,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
key, err := f.Users.VerifyGPGKey(context.Background())
if err != nil {
t.Fatal(err)
}
if key.ID != 12 || key.KeyID != "QRST7890" || !key.Verified {
t.Errorf("unexpected key: %+v", key)
}
}
func TestUserService_ListTokens_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/users/alice/tokens" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.AccessToken{
{ID: 1, Name: "ci", Scopes: []string{"repo"}},
{ID: 2, Name: "deploy", Scopes: []string{"read:packages"}},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
tokens, err := f.Users.ListTokens(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(tokens) != 2 || tokens[0].Name != "ci" || tokens[1].Name != "deploy" {
t.Fatalf("unexpected tokens: %+v", tokens)
}
}
func TestUserService_CreateToken_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/users/alice/tokens" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateAccessTokenOption
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.Name != "ci" || len(body.Scopes) != 1 || body.Scopes[0] != "repo" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.AccessToken{
ID: 7,
Name: body.Name,
Scopes: body.Scopes,
Token: "abcdef0123456789",
TokenLastEight: "456789",
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
token, err := f.Users.CreateToken(context.Background(), "alice", &types.CreateAccessTokenOption{
Name: "ci",
Scopes: []string{"repo"},
})
if err != nil {
t.Fatal(err)
}
if token.ID != 7 || token.Name != "ci" || token.Token != "abcdef0123456789" {
t.Fatalf("unexpected token: %+v", token)
}
}
func TestUserService_DeleteToken_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/users/alice/tokens/ci" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteToken(context.Background(), "alice", "ci"); err != nil {
t.Fatal(err)
}
}
func TestUserService_ListUserKeys_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/users/alice/keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
if got := r.URL.Query().Get("fingerprint"); got != "abc123" {
t.Errorf("wrong fingerprint: %s", got)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.PublicKey{
{ID: 4, Title: "laptop", Fingerprint: "abc123"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
keys, err := f.Users.ListUserKeys(context.Background(), "alice", UserKeyListOptions{Fingerprint: "abc123"})
if err != nil {
t.Fatal(err)
}
if len(keys) != 1 || keys[0].Title != "laptop" {
t.Fatalf("unexpected keys: %+v", keys)
}
}
func TestUserService_ListUserGPGKeys_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/users/alice/gpg_keys" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.GPGKey{
{ID: 8, KeyID: "ABCD1234"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
keys, err := f.Users.ListUserGPGKeys(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(keys) != 1 || keys[0].KeyID != "ABCD1234" {
t.Fatalf("unexpected gpg keys: %+v", keys)
}
}
func TestUserService_ListOAuth2Applications_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/user/applications/oauth2" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.OAuth2Application{
{ID: 1, Name: "CLI", ClientID: "cli", RedirectURIs: []string{"http://localhost:3000/callback"}},
{ID: 2, Name: "Desktop", ClientID: "desktop"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
apps, err := f.Users.ListOAuth2Applications(context.Background())
if err != nil {
t.Fatal(err)
}
if len(apps) != 2 {
t.Fatalf("got %d applications, want 2", len(apps))
}
if apps[0].ID != 1 || apps[0].Name != "CLI" {
t.Errorf("unexpected first application: %+v", apps[0])
}
}
func TestUserService_CreateOAuth2Application_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/user/applications/oauth2" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateOAuth2ApplicationOptions
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.Name != "CLI" || !body.ConfidentialClient || len(body.RedirectURIs) != 1 || body.RedirectURIs[0] != "http://localhost:3000/callback" {
t.Fatalf("unexpected body: %+v", body)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(types.OAuth2Application{
ID: 1,
Name: body.Name,
ClientID: "cli",
ClientSecret: "secret",
ConfidentialClient: body.ConfidentialClient,
RedirectURIs: body.RedirectURIs,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
app, err := f.Users.CreateOAuth2Application(context.Background(), &types.CreateOAuth2ApplicationOptions{
Name: "CLI",
ConfidentialClient: true,
RedirectURIs: []string{"http://localhost:3000/callback"},
})
if err != nil {
t.Fatal(err)
}
if app.ID != 1 || app.ClientSecret != "secret" {
t.Errorf("unexpected application: %+v", app)
}
}
func TestUserService_GetOAuth2Application_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/user/applications/oauth2/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.OAuth2Application{
ID: 7,
Name: "CLI",
ClientID: "cli",
ConfidentialClient: true,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
app, err := f.Users.GetOAuth2Application(context.Background(), 7)
if err != nil {
t.Fatal(err)
}
if app.ID != 7 || app.ClientID != "cli" {
t.Errorf("unexpected application: %+v", app)
}
}
func TestUserService_UpdateOAuth2Application_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/user/applications/oauth2/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var body types.CreateOAuth2ApplicationOptions
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatal(err)
}
if body.Name != "CLI v2" || len(body.RedirectURIs) != 2 {
t.Fatalf("unexpected body: %+v", body)
}
json.NewEncoder(w).Encode(types.OAuth2Application{
ID: 7,
Name: body.Name,
ClientID: "cli",
ClientSecret: "new-secret",
ConfidentialClient: body.ConfidentialClient,
RedirectURIs: body.RedirectURIs,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
app, err := f.Users.UpdateOAuth2Application(context.Background(), 7, &types.CreateOAuth2ApplicationOptions{
Name: "CLI v2",
RedirectURIs: []string{"http://localhost:3000/callback", "http://localhost:3000/alt"},
ConfidentialClient: false,
})
if err != nil {
t.Fatal(err)
}
if app.Name != "CLI v2" || app.ClientSecret != "new-secret" {
t.Errorf("unexpected application: %+v", app)
}
}
func TestUserService_DeleteOAuth2Application_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/user/applications/oauth2/7" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
if err := f.Users.DeleteOAuth2Application(context.Background(), 7); err != nil {
t.Fatal(err)
}
}
func TestUserService_ListFollowers_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/users/alice/followers" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.User{
{ID: 2, UserName: "bob"},
{ID: 3, UserName: "charlie"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
followers, err := f.Users.ListFollowers(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(followers) != 2 {
t.Errorf("got %d followers, want 2", len(followers))
}
if followers[0].UserName != "bob" {
t.Errorf("got username=%q, want %q", followers[0].UserName, "bob")
}
}
func TestUserService_ListSubscriptions_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/users/alice/subscriptions" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
repos, err := f.Users.ListSubscriptions(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(repos) != 1 {
t.Fatalf("got %d repositories, want 1", len(repos))
}
if repos[0].Name != "go-forge" {
t.Errorf("got name=%q, want %q", repos[0].Name, "go-forge")
}
}
func TestUserService_IterSubscriptions_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/users/alice/subscriptions" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for repo, err := range f.Users.IterSubscriptions(context.Background(), "alice") {
if err != nil {
t.Fatal(err)
}
count++
if repo.Name != "go-forge" {
t.Errorf("got name=%q, want %q", repo.Name, "go-forge")
}
}
if count != 1 {
t.Fatalf("got %d repositories, want 1", count)
}
}
func TestUserService_ListMyStarred_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/user/starred" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
repos, err := f.Users.ListMyStarred(context.Background())
if err != nil {
t.Fatal(err)
}
if len(repos) != 1 {
t.Fatalf("got %d repositories, want 1", len(repos))
}
if repos[0].FullName != "core/go-forge" {
t.Errorf("got full_name=%q, want %q", repos[0].FullName, "core/go-forge")
}
}
func TestUserService_IterMyStarred_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/user/starred" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Repository{
{Name: "go-forge", FullName: "core/go-forge"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
count := 0
for repo, err := range f.Users.IterMyStarred(context.Background()) {
if err != nil {
t.Fatal(err)
}
count++
if repo.Name != "go-forge" {
t.Errorf("got name=%q, want %q", repo.Name, "go-forge")
}
}
if count != 1 {
t.Fatalf("got %d repositories, want 1", count)
}
}
func TestUserService_CheckStarring_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/user/starred/core/go-forge" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
starring, err := f.Users.CheckStarring(context.Background(), "core", "go-forge")
if err != nil {
t.Fatal(err)
}
if !starring {
t.Fatal("got starring=false, want true")
}
}
func TestUserService_CheckStarring_Bad_NotFound(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/user/starred/core/go-forge" {
t.Errorf("wrong path: %s", r.URL.Path)
}
http.NotFound(w, r)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
starring, err := f.Users.CheckStarring(context.Background(), "core", "go-forge")
if err != nil {
t.Fatal(err)
}
if starring {
t.Fatal("got starring=true, want false")
}
}
func TestUserService_GetHeatmap_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/users/alice/heatmap" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode([]types.UserHeatmapData{
{Contributions: 3},
{Contributions: 7},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
heatmap, err := f.Users.GetHeatmap(context.Background(), "alice")
if err != nil {
t.Fatal(err)
}
if len(heatmap) != 2 {
t.Fatalf("got %d heatmap points, want 2", len(heatmap))
}
if heatmap[0].Contributions != 3 || heatmap[1].Contributions != 7 {
t.Errorf("unexpected heatmap data: %+v", heatmap)
}
}