Skip to content

Commit 12af99b

Browse files
CopilotJoannaaKL
authored andcommitted
Add endpoint constants and migrate raw package tests
Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com>
1 parent 3c453dd commit 12af99b

File tree

3 files changed

+192
-55
lines changed

3 files changed

+192
-55
lines changed

pkg/github/helper_test.go

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,120 @@ import (
1818
// GitHub API endpoint patterns for testing
1919
// These constants define the URL patterns used in HTTP mocking for tests
2020
const (
21+
// User endpoints
22+
GetUser = "GET /user"
23+
GetUserStarred = "GET /user/starred"
24+
GetUsersGistsByUsername = "GET /users/{username}/gists"
25+
GetUsersStarredByUsername = "GET /users/{username}/starred"
26+
PutUserStarredByOwnerByRepo = "PUT /user/starred/{owner}/{repo}"
27+
DeleteUserStarredByOwnerByRepo = "DELETE /user/starred/{owner}/{repo}"
28+
2129
// Repository endpoints
22-
GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}"
30+
GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}"
31+
GetReposBranchesByOwnerByRepo = "GET /repos/{owner}/{repo}/branches"
32+
GetReposTagsByOwnerByRepo = "GET /repos/{owner}/{repo}/tags"
33+
GetReposCommitsByOwnerByRepo = "GET /repos/{owner}/{repo}/commits"
34+
GetReposCommitsByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}"
35+
GetReposContentsByOwnerByRepoByPath = "GET /repos/{owner}/{repo}/contents/{path}"
36+
PutReposContentsByOwnerByRepoByPath = "PUT /repos/{owner}/{repo}/contents/{path}"
37+
PostReposForksByOwnerByRepo = "POST /repos/{owner}/{repo}/forks"
38+
GetReposSubscriptionByOwnerByRepo = "GET /repos/{owner}/{repo}/subscription"
39+
PutReposSubscriptionByOwnerByRepo = "PUT /repos/{owner}/{repo}/subscription"
40+
DeleteReposSubscriptionByOwnerByRepo = "DELETE /repos/{owner}/{repo}/subscription"
2341

2442
// Git endpoints
25-
GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}"
43+
GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}"
44+
GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}"
45+
PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs"
46+
PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}"
47+
GetReposGitCommitsByOwnerByRepoByCommitSha = "GET /repos/{owner}/{repo}/git/commits/{commit_sha}"
48+
PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits"
49+
GetReposGitTagsByOwnerByRepoByTagSha = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}"
50+
PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees"
51+
GetReposCommitsStatusByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/status"
52+
GetReposCommitsStatusesByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/statuses"
53+
54+
// Issues endpoints
55+
GetReposIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}"
56+
GetReposIssuesCommentsByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments"
57+
PostReposIssuesByOwnerByRepo = "POST /repos/{owner}/{repo}/issues"
58+
PostReposIssuesCommentsByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments"
59+
PatchReposIssuesByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}"
60+
GetReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues"
61+
PostReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues"
62+
DeleteReposIssuesSubIssueByOwnerByRepoByIssueNumber = "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issues"
63+
PatchReposIssuesSubIssuesPriorityByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority"
64+
65+
// Pull request endpoints
66+
GetReposPullsByOwnerByRepo = "GET /repos/{owner}/{repo}/pulls"
67+
GetReposPullsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}"
68+
GetReposPullsFilesByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/files"
69+
GetReposPullsReviewsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews"
70+
PostReposPullsByOwnerByRepo = "POST /repos/{owner}/{repo}/pulls"
71+
PatchReposPullsByOwnerByRepoByPullNumber = "PATCH /repos/{owner}/{repo}/pulls/{pull_number}"
72+
PutReposPullsMergeByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge"
73+
PutReposPullsUpdateBranchByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch"
74+
PostReposPullsRequestedReviewersByOwnerByRepoByPullNumber = "POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers"
75+
76+
// Notifications endpoints
77+
GetNotifications = "GET /notifications"
78+
PutNotifications = "PUT /notifications"
79+
GetReposNotificationsByOwnerByRepo = "GET /repos/{owner}/{repo}/notifications"
80+
PutReposNotificationsByOwnerByRepo = "PUT /repos/{owner}/{repo}/notifications"
81+
GetNotificationsThreadsByThreadId = "GET /notifications/threads/{thread_id}"
82+
PatchNotificationsThreadsByThreadId = "PATCH /notifications/threads/{thread_id}"
83+
DeleteNotificationsThreadsByThreadId = "DELETE /notifications/threads/{thread_id}"
84+
PutNotificationsThreadsSubscriptionByThreadId = "PUT /notifications/threads/{thread_id}/subscription"
85+
DeleteNotificationsThreadsSubscriptionByThreadId = "DELETE /notifications/threads/{thread_id}/subscription"
86+
87+
// Gists endpoints
88+
GetGists = "GET /gists"
89+
GetGistsByGistId = "GET /gists/{gist_id}"
90+
PostGists = "POST /gists"
91+
PatchGistsByGistId = "PATCH /gists/{gist_id}"
92+
93+
// Releases endpoints
94+
GetReposReleasesByOwnerByRepo = "GET /repos/{owner}/{repo}/releases"
95+
GetReposReleasesLatestByOwnerByRepo = "GET /repos/{owner}/{repo}/releases/latest"
96+
GetReposReleasesTagsByOwnerByRepoByTag = "GET /repos/{owner}/{repo}/releases/tags/{tag}"
2697

2798
// Code scanning endpoints
2899
GetReposCodeScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/code-scanning/alerts"
29100
GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}"
101+
102+
// Secret scanning endpoints
103+
GetReposSecretScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/secret-scanning/alerts"
104+
GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}"
105+
106+
// Dependabot endpoints
107+
GetReposDependabotAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/dependabot/alerts"
108+
GetReposDependabotAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"
109+
110+
// Security advisories endpoints
111+
GetAdvisories = "GET /advisories"
112+
GetAdvisoriesByGhsaId = "GET /advisories/{ghsa_id}"
113+
114+
// Actions endpoints
115+
GetReposActionsWorkflowsByOwnerByRepo = "GET /repos/{owner}/{repo}/actions/workflows"
116+
PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId = "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches"
117+
GetReposActionsRunsJobsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs"
118+
GetReposActionsRunsArtifactsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts"
119+
GetReposActionsRunsTimingByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing"
120+
GetReposActionsJobsLogsByOwnerByRepoByJobId = "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs"
121+
DeleteReposActionsRunsLogsByOwnerByRepoByRunId = "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs"
122+
123+
// Search endpoints
124+
GetSearchCode = "GET /search/code"
125+
GetSearchIssues = "GET /search/issues"
126+
GetSearchRepositories = "GET /search/repositories"
127+
GetSearchUsers = "GET /search/users"
128+
129+
// Raw content endpoints (used for GitHub raw content API, not standard API)
130+
// These are used with the raw content client that interacts with raw.githubusercontent.com
131+
GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path}"
132+
GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path}"
133+
GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path}"
134+
GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path}"
30135
)
31136

32137
type expectations struct {
@@ -382,6 +487,27 @@ func matchPath(pattern, path string) bool {
382487
patternParts := strings.Split(strings.Trim(pattern, "/"), "/")
383488
pathParts := strings.Split(strings.Trim(path, "/"), "/")
384489

490+
// Handle patterns with wildcard path like {path:.*}
491+
if len(patternParts) > 0 {
492+
lastPart := patternParts[len(patternParts)-1]
493+
if strings.HasPrefix(lastPart, "{") && strings.Contains(lastPart, ":") && strings.HasSuffix(lastPart, "}") {
494+
// This is a wildcard pattern like {path:.*}
495+
// Check if all parts before the wildcard match
496+
if len(pathParts) < len(patternParts)-1 {
497+
return false
498+
}
499+
for i := 0; i < len(patternParts)-1; i++ {
500+
if strings.HasPrefix(patternParts[i], "{") && strings.HasSuffix(patternParts[i], "}") {
501+
continue // Path parameter matches anything
502+
}
503+
if patternParts[i] != pathParts[i] {
504+
return false
505+
}
506+
}
507+
return true
508+
}
509+
}
510+
385511
if len(patternParts) != len(pathParts) {
386512
return false
387513
}

pkg/raw/raw_mock.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

pkg/raw/raw_test.go

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,44 @@
11
package raw
22

33
import (
4+
"bytes"
45
"context"
6+
"io"
57
"net/http"
68
"net/url"
9+
"strings"
710
"testing"
811

912
"github.com/google/go-github/v79/github"
10-
"github.com/migueleliasweb/go-github-mock/src/mock"
1113
"github.com/stretchr/testify/require"
1214
)
1315

16+
// mockRawTransport is a custom HTTP transport for testing raw content API
17+
type mockRawTransport struct {
18+
statusCode int
19+
contentType string
20+
body string
21+
}
22+
23+
func (m *mockRawTransport) RoundTrip(req *http.Request) (*http.Response, error) {
24+
// Create a response with the configured status and body
25+
resp := &http.Response{
26+
StatusCode: m.statusCode,
27+
Header: make(http.Header),
28+
Body: io.NopCloser(bytes.NewBufferString(m.body)),
29+
Request: req,
30+
}
31+
if m.contentType != "" {
32+
resp.Header.Set("Content-Type", m.contentType)
33+
}
34+
return resp, nil
35+
}
36+
1437
func TestGetRawContent(t *testing.T) {
1538
base, _ := url.Parse("https://raw.example.com/")
1639

1740
tests := []struct {
1841
name string
19-
pattern mock.EndpointPattern
2042
opts *ContentOpts
2143
owner, repo, path string
2244
statusCode int
@@ -25,46 +47,51 @@ func TestGetRawContent(t *testing.T) {
2547
expectError string
2648
}{
2749
{
28-
name: "HEAD fetch success",
29-
pattern: GetRawReposContentsByOwnerByRepoByPath,
30-
opts: nil,
31-
owner: "octocat", repo: "hello", path: "README.md",
50+
name: "HEAD fetch success",
51+
opts: nil,
52+
owner: "octocat",
53+
repo: "hello",
54+
path: "README.md",
3255
statusCode: 200,
3356
contentType: "text/plain",
3457
body: "# Test file",
3558
},
3659
{
37-
name: "branch fetch success",
38-
pattern: GetRawReposContentsByOwnerByRepoByBranchByPath,
39-
opts: &ContentOpts{Ref: "refs/heads/main"},
40-
owner: "octocat", repo: "hello", path: "README.md",
60+
name: "branch fetch success",
61+
opts: &ContentOpts{Ref: "refs/heads/main"},
62+
owner: "octocat",
63+
repo: "hello",
64+
path: "README.md",
4165
statusCode: 200,
4266
contentType: "text/plain",
4367
body: "# Test file",
4468
},
4569
{
46-
name: "tag fetch success",
47-
pattern: GetRawReposContentsByOwnerByRepoByTagByPath,
48-
opts: &ContentOpts{Ref: "refs/tags/v1.0.0"},
49-
owner: "octocat", repo: "hello", path: "README.md",
70+
name: "tag fetch success",
71+
opts: &ContentOpts{Ref: "refs/tags/v1.0.0"},
72+
owner: "octocat",
73+
repo: "hello",
74+
path: "README.md",
5075
statusCode: 200,
5176
contentType: "text/plain",
5277
body: "# Test file",
5378
},
5479
{
55-
name: "sha fetch success",
56-
pattern: GetRawReposContentsByOwnerByRepoBySHAByPath,
57-
opts: &ContentOpts{SHA: "abc123"},
58-
owner: "octocat", repo: "hello", path: "README.md",
80+
name: "sha fetch success",
81+
opts: &ContentOpts{SHA: "abc123"},
82+
owner: "octocat",
83+
repo: "hello",
84+
path: "README.md",
5985
statusCode: 200,
6086
contentType: "text/plain",
6187
body: "# Test file",
6288
},
6389
{
64-
name: "not found",
65-
pattern: GetRawReposContentsByOwnerByRepoByPath,
66-
opts: nil,
67-
owner: "octocat", repo: "hello", path: "notfound.txt",
90+
name: "not found",
91+
opts: nil,
92+
owner: "octocat",
93+
repo: "hello",
94+
path: "notfound.txt",
6895
statusCode: 404,
6996
contentType: "application/json",
7097
body: `{"message": "Not Found"}`,
@@ -73,29 +100,33 @@ func TestGetRawContent(t *testing.T) {
73100

74101
for _, tc := range tests {
75102
t.Run(tc.name, func(t *testing.T) {
76-
mockedClient := mock.NewMockedHTTPClient(
77-
mock.WithRequestMatchHandler(
78-
tc.pattern,
79-
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
80-
w.Header().Set("Content-Type", tc.contentType)
81-
w.WriteHeader(tc.statusCode)
82-
_, err := w.Write([]byte(tc.body))
83-
require.NoError(t, err)
84-
}),
85-
),
86-
)
103+
// Create mock HTTP client with custom transport
104+
mockedClient := &http.Client{
105+
Transport: &mockRawTransport{
106+
statusCode: tc.statusCode,
107+
contentType: tc.contentType,
108+
body: tc.body,
109+
},
110+
}
87111
ghClient := github.NewClient(mockedClient)
88112
client := NewClient(ghClient, base)
89113
resp, err := client.GetRawContent(context.Background(), tc.owner, tc.repo, tc.path, tc.opts)
90114
defer func() {
91115
_ = resp.Body.Close()
92116
}()
117+
93118
if tc.expectError != "" {
94119
require.Error(t, err)
95120
return
96121
}
97122
require.NoError(t, err)
98123
require.Equal(t, tc.statusCode, resp.StatusCode)
124+
125+
// Verify the URL was constructed correctly
126+
actualURL := client.URLFromOpts(tc.opts, tc.owner, tc.repo, tc.path)
127+
require.True(t, strings.Contains(actualURL, tc.owner))
128+
require.True(t, strings.Contains(actualURL, tc.repo))
129+
require.True(t, strings.Contains(actualURL, tc.path))
99130
})
100131
}
101132
}

0 commit comments

Comments
 (0)