grafana/apps/provisioning/pkg/repository/github/impl_test.go

1722 lines
50 KiB
Go

package github
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"testing"
"time"
"github.com/google/go-github/v70/github"
mockhub "github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGithubClient_GetCommits(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
branch string
path string
since time.Time
until time.Time
wantCommits []Commit
wantErr error
}{
{
name: "get commits successfully",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
commits := []*github.RepositoryCommit{
{
SHA: github.Ptr("abc123"),
Commit: &github.Commit{
Message: github.Ptr("First commit"),
Author: &github.CommitAuthor{
Name: github.Ptr("Test User"),
Email: github.Ptr("test@example.com"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)},
},
Committer: &github.CommitAuthor{
Name: github.Ptr("Test User"),
Email: github.Ptr("test@example.com"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)},
},
},
Author: &github.User{
Login: github.Ptr("test-user"),
AvatarURL: github.Ptr("https://avatar.url"),
},
Committer: &github.User{
Login: github.Ptr("test-user"),
AvatarURL: github.Ptr("https://avatar.url"),
},
},
{
SHA: github.Ptr("def456"),
Commit: &github.Commit{
Message: github.Ptr("Second commit"),
Author: &github.CommitAuthor{
Name: github.Ptr("Another User"),
Email: github.Ptr("another@example.com"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 2, 12, 0, 0, 0, time.UTC)},
},
Committer: &github.CommitAuthor{
Name: github.Ptr("Another User"),
Email: github.Ptr("another@example.com"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 2, 12, 0, 0, 0, time.UTC)},
},
},
Author: &github.User{
Login: github.Ptr("another-user"),
AvatarURL: github.Ptr("https://another.avatar.url"),
},
Committer: &github.User{
Login: github.Ptr("another-user"),
AvatarURL: github.Ptr("https://another.avatar.url"),
},
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(commits))
}),
),
),
owner: "test-owner",
repository: "test-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: []Commit{
{
Ref: "abc123",
Message: "First commit",
Author: &CommitAuthor{
Name: "Test User",
Username: "test-user",
AvatarURL: "https://avatar.url",
},
Committer: &CommitAuthor{
Name: "Test User",
Username: "test-user",
AvatarURL: "https://avatar.url",
},
CreatedAt: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC),
},
{
Ref: "def456",
Message: "Second commit",
Author: &CommitAuthor{
Name: "Another User",
Username: "another-user",
AvatarURL: "https://another.avatar.url",
},
Committer: &CommitAuthor{
Name: "Another User",
Username: "another-user",
AvatarURL: "https://another.avatar.url",
},
CreatedAt: time.Date(2023, 1, 2, 12, 0, 0, 0, time.UTC),
},
},
wantErr: nil,
},
{
name: "repository not found",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusNotFound,
},
Message: "Not Found",
}))
}),
),
),
owner: "test-owner",
repository: "nonexistent-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: nil,
wantErr: ErrResourceNotFound,
},
{
name: "commits missing author",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
commits := []*github.RepositoryCommit{
{
SHA: github.Ptr("abc123"),
Commit: &github.Commit{
Message: github.Ptr("First commit"),
Author: &github.CommitAuthor{
Name: github.Ptr("Test User"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)},
Email: github.Ptr("test@example.com"),
},
Committer: &github.CommitAuthor{
Name: github.Ptr("Test User"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)},
Email: github.Ptr("test@example.com"),
},
},
// Author is nil
Committer: &github.User{
Login: github.Ptr("test-user"),
AvatarURL: github.Ptr("https://avatar.url"),
},
},
{
SHA: github.Ptr("def456"),
Commit: &github.Commit{
Message: github.Ptr("Second commit"),
// Missing Author in Commit
Committer: &github.CommitAuthor{
Name: github.Ptr("Another User"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 2, 12, 0, 0, 0, time.UTC)},
Email: github.Ptr("another@example.com"),
},
},
Author: &github.User{
Login: github.Ptr("another-user"),
AvatarURL: github.Ptr("https://another.avatar.url"),
},
Committer: &github.User{
Login: github.Ptr("another-user"),
AvatarURL: github.Ptr("https://another.avatar.url"),
},
},
}
require.NoError(t, json.NewEncoder(w).Encode(commits))
}),
),
),
owner: "test-owner",
repository: "test-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: []Commit{
{
Ref: "abc123",
Message: "First commit",
Author: &CommitAuthor{
Name: "Test User",
// Username and AvatarURL are empty because Author is nil in the response
},
Committer: &CommitAuthor{
Name: "Test User",
Username: "test-user",
AvatarURL: "https://avatar.url",
},
CreatedAt: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC),
},
{
Ref: "def456",
Message: "Second commit",
Author: nil, // Author is nil because Commit.Author is nil in the response
Committer: &CommitAuthor{
Name: "Another User",
Username: "another-user",
AvatarURL: "https://another.avatar.url",
},
},
},
wantErr: nil,
},
{
name: "too many commits",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
// Return a large number of commits that would exceed the maxCommits limit
commits := make([]*github.RepositoryCommit, maxCommits+1)
for i := 0; i < maxCommits+1; i++ {
commits[i] = &github.RepositoryCommit{
SHA: github.Ptr(fmt.Sprintf("commit%d", i)),
Commit: &github.Commit{
Message: github.Ptr(fmt.Sprintf("Commit %d", i)),
Author: &github.CommitAuthor{
Name: github.Ptr("Test User"),
Date: &github.Timestamp{Time: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)},
Email: github.Ptr("test@example.com"),
},
},
Author: &github.User{
Login: github.Ptr("test-user"),
AvatarURL: github.Ptr("https://avatar.url"),
},
}
}
require.NoError(t, json.NewEncoder(w).Encode(commits))
}),
),
),
owner: "test-owner",
repository: "test-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: nil,
wantErr: fmt.Errorf("too many commits to fetch (more than %d)", maxCommits),
},
{
name: "service unavailable",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: nil,
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposCommitsByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
branch: "main",
path: "test.txt",
since: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
until: time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC),
wantCommits: nil,
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
commits, err := client.Commits(context.Background(), tt.owner, tt.repository, tt.branch, tt.path)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
assert.Nil(t, commits)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.wantCommits, commits)
}
})
}
}
func TestGithubClient_ListWebhooks(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
wantWebhooks []WebhookConfig
wantErr error
}{
{
name: "successful webhooks listing",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
hooks := []*github.Hook{
{
ID: github.Ptr(int64(1)),
Events: []string{"push", "pull_request"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook1"),
ContentType: github.Ptr("json"),
},
},
{
ID: github.Ptr(int64(2)),
Events: []string{"issues"},
Active: github.Ptr(false),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook2"),
ContentType: github.Ptr(""),
},
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(hooks))
}),
),
),
owner: "test-owner",
repository: "test-repo",
wantWebhooks: []WebhookConfig{
{
ID: 1,
Events: []string{"push", "pull_request"},
Active: true,
URL: "https://example.com/webhook1",
ContentType: "json",
},
{
ID: 2,
Events: []string{"issues"},
Active: false,
URL: "https://example.com/webhook2",
ContentType: "form", // Default value when empty
},
},
wantErr: nil,
},
{
name: "empty webhooks list",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
hooks := []*github.Hook{}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(hooks))
}),
),
),
owner: "test-owner",
repository: "test-repo",
wantWebhooks: []WebhookConfig{},
wantErr: nil,
},
{
name: "too many webhooks",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
// Create more webhooks than the maxWebhooks limit
hooks := make([]*github.Hook, maxWebhooks+1)
for i := 0; i < maxWebhooks+1; i++ {
hooks[i] = &github.Hook{
ID: github.Ptr(int64(i + 1)),
Events: []string{"push"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr(fmt.Sprintf("https://example.com/webhook%d", i+1)),
ContentType: github.Ptr("json"),
},
}
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(hooks))
}),
),
),
owner: "test-owner",
repository: "test-repo",
wantWebhooks: nil,
wantErr: fmt.Errorf("too many webhooks configured (more than %d)", maxWebhooks),
},
{
name: "service unavailable error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
wantWebhooks: nil,
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
wantWebhooks: nil,
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
webhooks, err := client.ListWebhooks(context.Background(), tt.owner, tt.repository)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
// Check the result
assert.Equal(t, tt.wantWebhooks, webhooks)
})
}
}
func TestGithubClient_CreateWebhook(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
config WebhookConfig
want WebhookConfig
wantErr error
}{
{
name: "successful webhook creation",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the request body contains the correct webhook config
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
hook := &github.Hook{}
require.NoError(t, json.Unmarshal(body, hook))
assert.Equal(t, "https://example.com/webhook", hook.Config.GetURL())
assert.Equal(t, "json", hook.Config.GetContentType())
assert.Equal(t, "secret123", hook.Config.GetSecret())
assert.Equal(t, []string{"push", "pull_request"}, hook.Events)
assert.True(t, hook.GetActive())
// Return a created hook
createdHook := &github.Hook{
ID: github.Ptr(int64(123)),
Events: []string{"push", "pull_request"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook"),
ContentType: github.Ptr("json"),
// Secret is not returned by GitHub API
},
}
w.WriteHeader(http.StatusCreated)
require.NoError(t, json.NewEncoder(w).Encode(createdHook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
Events: []string{"push", "pull_request"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
want: WebhookConfig{
ID: 123,
Events: []string{"push", "pull_request"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
wantErr: nil,
},
{
name: "default content type to form",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
hook := &github.Hook{}
require.NoError(t, json.Unmarshal(body, hook))
// Verify content type was defaulted to "form"
assert.Equal(t, "form", hook.Config.GetContentType())
createdHook := &github.Hook{
ID: github.Ptr(int64(123)),
Events: []string{"push"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook"),
ContentType: github.Ptr("form"),
},
}
w.WriteHeader(http.StatusCreated)
require.NoError(t, json.NewEncoder(w).Encode(createdHook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
Secret: "secret123",
// ContentType intentionally omitted
},
want: WebhookConfig{
ID: 123,
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "form",
Secret: "secret123",
},
wantErr: nil,
},
{
name: "service unavailable error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
want: WebhookConfig{},
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposHooksByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
want: WebhookConfig{},
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
got, err := client.CreateWebhook(context.Background(), tt.owner, tt.repository, tt.config)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
// Check the result
assert.Equal(t, tt.want, got)
})
}
}
func TestGithubClient_GetWebhook(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
webhookID int64
want WebhookConfig
wantErr error
}{
{
name: "successful webhook retrieval",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
hook := &github.Hook{
ID: github.Ptr(int64(123)),
Events: []string{"push", "pull_request"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook"),
ContentType: github.Ptr("json"),
// Secret is not returned by GitHub API
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(hook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 123,
want: WebhookConfig{
ID: 123,
Events: []string{"push", "pull_request"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
},
wantErr: nil,
},
{
name: "empty content type defaults to json",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
hook := &github.Hook{
ID: github.Ptr(int64(456)),
Events: []string{"push"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook-empty-content"),
ContentType: github.Ptr(""), // Empty content type
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(hook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 456,
want: WebhookConfig{
ID: 456,
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook-empty-content",
ContentType: "json", // Should default to "json"
},
wantErr: nil,
},
{
name: "webhook not found",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusNotFound,
},
Message: "Not Found",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 999,
want: WebhookConfig{},
wantErr: ErrResourceNotFound,
},
{
name: "service unavailable",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service Unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 123,
want: WebhookConfig{},
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 123,
want: WebhookConfig{},
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
got, err := client.GetWebhook(context.Background(), tt.owner, tt.repository, tt.webhookID)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
// Check the result
assert.Equal(t, tt.want, got)
})
}
}
func TestGithubClient_DeleteWebhook(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
webhookID int64
wantErr error
}{
{
name: "successful webhook deletion",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 123,
wantErr: nil,
},
{
name: "webhook not found",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusNotFound,
},
Message: "Not found",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 456,
wantErr: ErrResourceNotFound,
},
{
name: "service unavailable",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 789,
wantErr: ErrServiceUnavailable,
},
{
name: "unauthorized to delete the webhook",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusUnauthorized,
},
Message: "401 bad credentials",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 789,
wantErr: ErrUnauthorized,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
webhookID: 101,
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
err := client.DeleteWebhook(context.Background(), tt.owner, tt.repository, tt.webhookID)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestGithubClient_EditWebhook(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
config WebhookConfig
wantErr error
}{
{
name: "successful webhook edit",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PatchReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the request body contains the correct webhook config
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
hook := &github.Hook{}
require.NoError(t, json.Unmarshal(body, hook))
assert.Equal(t, "https://example.com/webhook-updated", hook.Config.GetURL())
assert.Equal(t, "json", hook.Config.GetContentType())
assert.Equal(t, "updated-secret", hook.Config.GetSecret())
assert.Equal(t, []string{"push", "pull_request", "issues"}, hook.Events)
assert.True(t, hook.GetActive())
// Return the updated hook
updatedHook := &github.Hook{
ID: github.Ptr(int64(123)),
Events: []string{"push", "pull_request", "issues"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook-updated"),
ContentType: github.Ptr("json"),
// Secret is not returned by GitHub API
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(updatedHook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
ID: 123,
Events: []string{"push", "pull_request", "issues"},
Active: true,
URL: "https://example.com/webhook-updated",
ContentType: "json",
Secret: "updated-secret",
},
wantErr: nil,
},
{
name: "default content type to form",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PatchReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the request body contains the correct webhook config
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
hook := &github.Hook{}
require.NoError(t, json.Unmarshal(body, hook))
// Verify content type was defaulted to "form"
assert.Equal(t, "form", hook.Config.GetContentType())
assert.Equal(t, "https://example.com/webhook", hook.Config.GetURL())
assert.Equal(t, "secret123", hook.Config.GetSecret())
assert.Equal(t, []string{"push"}, hook.Events)
assert.True(t, hook.GetActive())
// Return the updated hook
updatedHook := &github.Hook{
ID: github.Ptr(int64(123)),
Events: []string{"push"},
Active: github.Ptr(true),
Config: &github.HookConfig{
URL: github.Ptr("https://example.com/webhook"),
ContentType: github.Ptr("form"),
// Secret is not returned by GitHub API
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(updatedHook))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
ID: 123,
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "", // Empty content type should default to "form"
Secret: "secret123",
},
wantErr: nil,
},
{
name: "service unavailable error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PatchReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
ID: 123,
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PatchReposHooksByOwnerByRepoByHookId,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
config: WebhookConfig{
ID: 123,
Events: []string{"push"},
Active: true,
URL: "https://example.com/webhook",
ContentType: "json",
Secret: "secret123",
},
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
err := client.EditWebhook(context.Background(), tt.owner, tt.repository, tt.config)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestGithubClient_ListPullRequestFiles(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
number int
wantFiles []CommitFile
wantErr error
}{
{
name: "successful pull request files listing",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposPullsFilesByOwnerByRepoByPullNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
files := []*github.CommitFile{
{
Filename: github.Ptr("file1.txt"),
Additions: github.Ptr(10),
Deletions: github.Ptr(5),
Changes: github.Ptr(15),
Status: github.Ptr("modified"),
Patch: github.Ptr("@@ -1,5 +1,10 @@"),
},
{
Filename: github.Ptr("file2.txt"),
Additions: github.Ptr(20),
Deletions: github.Ptr(0),
Changes: github.Ptr(20),
Status: github.Ptr("added"),
Patch: github.Ptr("@@ -0,0 +1,20 @@"),
},
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(files))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 123,
wantFiles: []CommitFile{
&github.CommitFile{
Filename: github.Ptr("file1.txt"),
Additions: github.Ptr(10),
Deletions: github.Ptr(5),
Changes: github.Ptr(15),
Status: github.Ptr("modified"),
Patch: github.Ptr("@@ -1,5 +1,10 @@"),
},
&github.CommitFile{
Filename: github.Ptr("file2.txt"),
Additions: github.Ptr(20),
Deletions: github.Ptr(0),
Changes: github.Ptr(20),
Status: github.Ptr("added"),
Patch: github.Ptr("@@ -0,0 +1,20 @@"),
},
},
wantErr: nil,
},
{
name: "empty files list",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposPullsFilesByOwnerByRepoByPullNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
files := []*github.CommitFile{}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(files))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 456,
wantFiles: []CommitFile{},
wantErr: nil,
},
{
name: "too many files",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposPullsFilesByOwnerByRepoByPullNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
// Create more files than the maxPRFiles limit
files := make([]*github.CommitFile, maxPRFiles+1)
for i := 0; i < maxPRFiles+1; i++ {
files[i] = &github.CommitFile{
Filename: github.Ptr(fmt.Sprintf("file%d.txt", i+1)),
Additions: github.Ptr(i + 1),
Deletions: github.Ptr(0),
Changes: github.Ptr(i + 1),
Status: github.Ptr("added"),
}
}
w.WriteHeader(http.StatusOK)
require.NoError(t, json.NewEncoder(w).Encode(files))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 789,
wantFiles: nil,
wantErr: fmt.Errorf("pull request contains too many files (more than %d)", maxPRFiles),
},
{
name: "service unavailable error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposPullsFilesByOwnerByRepoByPullNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 101,
wantFiles: nil,
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.GetReposPullsFilesByOwnerByRepoByPullNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 202,
wantFiles: nil,
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
files, err := client.ListPullRequestFiles(context.Background(), tt.owner, tt.repository, tt.number)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
// Check the result
assert.Equal(t, tt.wantFiles, files)
})
}
}
func TestCreatePullRequestComment(t *testing.T) {
tests := []struct {
name string
mockHandler *http.Client
owner string
repository string
number int
body string
wantErr error
}{
{
name: "successful comment creation",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposIssuesCommentsByOwnerByRepoByIssueNumber,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the request body contains the correct comment
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
comment := &github.IssueComment{}
require.NoError(t, json.Unmarshal(body, comment))
assert.Equal(t, "Test comment", comment.GetBody())
// Return the created comment
createdComment := &github.IssueComment{
ID: github.Ptr(int64(123)),
Body: github.Ptr("Test comment"),
}
w.WriteHeader(http.StatusCreated)
require.NoError(t, json.NewEncoder(w).Encode(createdComment))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 101,
body: "Test comment",
wantErr: nil,
},
{
name: "service unavailable error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposIssuesCommentsByOwnerByRepoByIssueNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
Message: "Service unavailable",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 101,
body: "Test comment",
wantErr: ErrServiceUnavailable,
},
{
name: "other error",
mockHandler: mockhub.NewMockedHTTPClient(
mockhub.WithRequestMatchHandler(
mockhub.PostReposIssuesCommentsByOwnerByRepoByIssueNumber,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusInternalServerError,
},
Message: "Internal server error",
}))
}),
),
),
owner: "test-owner",
repository: "test-repo",
number: 101,
body: "Test comment",
wantErr: errors.New("Internal server error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock client
factory := ProvideFactory()
factory.Client = tt.mockHandler
client := factory.New(context.Background(), "")
// Call the method being tested
err := client.CreatePullRequestComment(context.Background(), tt.owner, tt.repository, tt.number, tt.body)
// Check the error
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestPaginatedList(t *testing.T) {
tests := []struct {
name string
mockSetup func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions)
want []string
wantErr error
}{
{
name: "single page",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
items := []string{"item1", "item2", "item3"}
listFn := func(_ context.Context, _ *github.ListOptions) ([]string, *github.Response, error) {
return items, &github.Response{
NextPage: 0,
}, nil
}
return listFn, defaultListOptions(100)
},
want: []string{"item1", "item2", "item3"},
wantErr: nil,
},
{
name: "multiple pages",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
page1 := []string{"item1", "item2"}
page2 := []string{"item3", "item4"}
page3 := []string{"item5"}
var callCount int
listFn := func(_ context.Context, opts *github.ListOptions) ([]string, *github.Response, error) {
callCount++
switch callCount {
case 1:
return page1, &github.Response{
NextPage: 2,
}, nil
case 2:
assert.Equal(t, 2, opts.Page)
return page2, &github.Response{
NextPage: 3,
}, nil
case 3:
assert.Equal(t, 3, opts.Page)
return page3, &github.Response{
NextPage: 0,
}, nil
default:
return nil, nil, errors.New("unexpected call")
}
}
return listFn, defaultListOptions(100)
},
want: []string{"item1", "item2", "item3", "item4", "item5"},
wantErr: nil,
},
{
name: "error on first page",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
listFn := func(_ context.Context, _ *github.ListOptions) ([]string, *github.Response, error) {
return nil, &github.Response{}, errors.New("API error")
}
return listFn, defaultListOptions(100)
},
want: nil,
wantErr: errors.New("API error"),
},
{
name: "service unavailable error",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
listFn := func(_ context.Context, _ *github.ListOptions) ([]string, *github.Response, error) {
return nil, &github.Response{}, &github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusServiceUnavailable,
},
}
}
return listFn, defaultListOptions(100)
},
want: nil,
wantErr: ErrServiceUnavailable,
},
{
name: "resource not found error",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
listFn := func(_ context.Context, _ *github.ListOptions) ([]string, *github.Response, error) {
return nil, &github.Response{}, &github.ErrorResponse{
Response: &http.Response{
StatusCode: http.StatusNotFound,
},
}
}
return listFn, defaultListOptions(100)
},
want: nil,
wantErr: ErrResourceNotFound,
},
{
name: "too many items error",
mockSetup: func() (func(context.Context, *github.ListOptions) ([]string, *github.Response, error), listOptions) {
listFn := func(_ context.Context, _ *github.ListOptions) ([]string, *github.Response, error) {
// Return more items than the max allowed
items := make([]string, 10)
for i := range items {
items[i] = fmt.Sprintf("item%d", i+1)
}
return items, &github.Response{
NextPage: 2,
}, nil
}
return listFn, listOptions{
ListOptions: github.ListOptions{
Page: 1,
PerPage: 100,
},
MaxItems: 5, // Set max items to less than what we'll return
}
},
want: nil,
wantErr: ErrTooManyItems,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
listFn, opts := tt.mockSetup()
got, err := paginatedList(context.Background(), listFn, opts)
if tt.wantErr != nil {
assert.Error(t, err)
if errors.Is(err, tt.wantErr) {
assert.Equal(t, tt.wantErr, err)
} else {
assert.Contains(t, err.Error(), tt.wantErr.Error())
}
assert.Nil(t, got)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}
func TestDefaultListOptions(t *testing.T) {
tests := []struct {
name string
maxItems int
want listOptions
}{
{
name: "with zero max items",
maxItems: 0,
want: listOptions{
ListOptions: github.ListOptions{
Page: 1,
PerPage: 100,
},
MaxItems: 0,
},
},
{
name: "with positive max items",
maxItems: 50,
want: listOptions{
ListOptions: github.ListOptions{
Page: 1,
PerPage: 100,
},
MaxItems: 50,
},
},
{
name: "with large max items",
maxItems: 1000,
want: listOptions{
ListOptions: github.ListOptions{
Page: 1,
PerPage: 100,
},
MaxItems: 1000,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := defaultListOptions(tt.maxItems)
assert.Equal(t, tt.want, got)
})
}
}