Skip to content

Commit b9dfd36

Browse files
committed
increase test coverage
1 parent a7e0f6e commit b9dfd36

2 files changed

Lines changed: 377 additions & 1 deletion

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Set up Go
1919
uses: actions/setup-go@v5
2020
with:
21-
go-version: '1.23'
21+
go-version: '1.25'
2222
cache: true
2323

2424
- name: Download dependencies

pkg/prx/github/platform_test.go

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
//nolint:errcheck // Test handlers don't need to check w.Write errors
2+
package github
3+
4+
import (
5+
"context"
6+
"log/slog"
7+
"net/http"
8+
"net/http/httptest"
9+
"os"
10+
"testing"
11+
)
12+
13+
func TestWithLogger(t *testing.T) {
14+
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
15+
platform := NewPlatform("test-token", WithLogger(logger))
16+
17+
if platform.logger != logger {
18+
t.Error("Expected custom logger to be set")
19+
}
20+
}
21+
22+
func TestWithHTTPClient(t *testing.T) {
23+
customClient := &http.Client{
24+
Timeout: 60,
25+
}
26+
27+
platform := NewPlatform("test-token", WithHTTPClient(customClient))
28+
29+
if platform.client.HTTPClient == nil {
30+
t.Error("Expected HTTP client to be set")
31+
}
32+
33+
// Verify transport was wrapped
34+
if _, ok := platform.client.HTTPClient.Transport.(*Transport); !ok {
35+
t.Error("Expected transport to be wrapped with retry Transport")
36+
}
37+
}
38+
39+
func TestWithHTTPClient_ExistingTransport(t *testing.T) {
40+
customTransport := &http.Transport{}
41+
customClient := &http.Client{
42+
Transport: customTransport,
43+
}
44+
45+
platform := NewPlatform("test-token", WithHTTPClient(customClient))
46+
47+
// Verify existing transport was wrapped
48+
if transport, ok := platform.client.HTTPClient.Transport.(*Transport); !ok {
49+
t.Error("Expected transport to be wrapped")
50+
} else if transport.Base != customTransport {
51+
t.Error("Expected base transport to be the custom transport")
52+
}
53+
}
54+
55+
func TestWithHTTPClient_AlreadyWrapped(t *testing.T) {
56+
wrappedTransport := &Transport{Base: http.DefaultTransport}
57+
customClient := &http.Client{
58+
Transport: wrappedTransport,
59+
}
60+
61+
platform := NewPlatform("test-token", WithHTTPClient(customClient))
62+
63+
// Verify transport is not double-wrapped
64+
if transport, ok := platform.client.HTTPClient.Transport.(*Transport); !ok {
65+
t.Error("Expected transport to remain as Transport")
66+
} else if transport != wrappedTransport {
67+
t.Error("Expected transport to not be double-wrapped")
68+
}
69+
}
70+
71+
func TestCalculateTestStateFromGraphQL(t *testing.T) {
72+
tests := []struct {
73+
name string
74+
data *graphQLPullRequestComplete
75+
wantState string
76+
}{
77+
{
78+
name: "no status check rollup",
79+
data: &graphQLPullRequestComplete{},
80+
wantState: "",
81+
},
82+
{
83+
name: "failing test",
84+
data: &graphQLPullRequestComplete{
85+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
86+
{
87+
TypeName: "CheckRun",
88+
Name: "unit-tests",
89+
Status: "completed",
90+
Conclusion: "failure",
91+
},
92+
}),
93+
},
94+
wantState: "failing",
95+
},
96+
{
97+
name: "running test",
98+
data: &graphQLPullRequestComplete{
99+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
100+
{
101+
TypeName: "CheckRun",
102+
Name: "test-check",
103+
Status: "in_progress",
104+
},
105+
}),
106+
},
107+
wantState: "running",
108+
},
109+
{
110+
name: "queued test",
111+
data: &graphQLPullRequestComplete{
112+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
113+
{
114+
TypeName: "CheckRun",
115+
Name: "CI-test",
116+
Status: "queued",
117+
},
118+
}),
119+
},
120+
wantState: "queued",
121+
},
122+
{
123+
name: "passing tests",
124+
data: &graphQLPullRequestComplete{
125+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
126+
{
127+
TypeName: "CheckRun",
128+
Name: "test-suite",
129+
Status: "completed",
130+
Conclusion: "success",
131+
},
132+
}),
133+
},
134+
wantState: "passing",
135+
},
136+
{
137+
name: "non-test check run ignored",
138+
data: &graphQLPullRequestComplete{
139+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
140+
{
141+
TypeName: "CheckRun",
142+
Name: "lint",
143+
Status: "completed",
144+
Conclusion: "failure",
145+
},
146+
}),
147+
},
148+
wantState: "passing",
149+
},
150+
{
151+
name: "non-CheckRun type ignored",
152+
data: &graphQLPullRequestComplete{
153+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
154+
{
155+
TypeName: "StatusContext",
156+
Name: "test-status",
157+
Status: "completed",
158+
Conclusion: "failure",
159+
},
160+
}),
161+
},
162+
wantState: "passing",
163+
},
164+
{
165+
name: "timed out test",
166+
data: &graphQLPullRequestComplete{
167+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
168+
{
169+
TypeName: "CheckRun",
170+
Name: "test-timeout",
171+
Status: "completed",
172+
Conclusion: "timed_out",
173+
},
174+
}),
175+
},
176+
wantState: "failing",
177+
},
178+
{
179+
name: "action required test",
180+
data: &graphQLPullRequestComplete{
181+
HeadRef: makeHeadRef([]graphQLStatusCheckNode{
182+
{
183+
TypeName: "CheckRun",
184+
Name: "check-required",
185+
Status: "completed",
186+
Conclusion: "action_required",
187+
},
188+
}),
189+
},
190+
wantState: "failing",
191+
},
192+
}
193+
194+
for _, tt := range tests {
195+
t.Run(tt.name, func(t *testing.T) {
196+
p := &Platform{}
197+
state := p.calculateTestStateFromGraphQL(tt.data)
198+
if state != tt.wantState {
199+
t.Errorf("Expected state %q, got %q", tt.wantState, state)
200+
}
201+
})
202+
}
203+
}
204+
205+
// Helper function to create HeadRef with status check nodes
206+
func makeHeadRef(nodes []graphQLStatusCheckNode) struct {
207+
Target struct {
208+
StatusCheckRollup *struct {
209+
Contexts struct {
210+
Nodes []graphQLStatusCheckNode `json:"nodes"`
211+
} `json:"contexts"`
212+
State string `json:"state"`
213+
} `json:"statusCheckRollup"`
214+
OID string `json:"oid"`
215+
} `json:"target"`
216+
Name string `json:"name"`
217+
} {
218+
return struct {
219+
Target struct {
220+
StatusCheckRollup *struct {
221+
Contexts struct {
222+
Nodes []graphQLStatusCheckNode `json:"nodes"`
223+
} `json:"contexts"`
224+
State string `json:"state"`
225+
} `json:"statusCheckRollup"`
226+
OID string `json:"oid"`
227+
} `json:"target"`
228+
Name string `json:"name"`
229+
}{
230+
Target: struct {
231+
StatusCheckRollup *struct {
232+
Contexts struct {
233+
Nodes []graphQLStatusCheckNode `json:"nodes"`
234+
} `json:"contexts"`
235+
State string `json:"state"`
236+
} `json:"statusCheckRollup"`
237+
OID string `json:"oid"`
238+
}{
239+
StatusCheckRollup: &struct {
240+
Contexts struct {
241+
Nodes []graphQLStatusCheckNode `json:"nodes"`
242+
} `json:"contexts"`
243+
State string `json:"state"`
244+
}{
245+
Contexts: struct {
246+
Nodes []graphQLStatusCheckNode `json:"nodes"`
247+
}{
248+
Nodes: nodes,
249+
},
250+
},
251+
},
252+
}
253+
}
254+
255+
func TestExecuteGraphQL_ErrorHandling(t *testing.T) {
256+
tests := []struct {
257+
name string
258+
serverHandler http.HandlerFunc
259+
wantErr bool
260+
}{
261+
{
262+
name: "graphql error in response",
263+
serverHandler: func(w http.ResponseWriter, r *http.Request) {
264+
w.WriteHeader(http.StatusOK)
265+
w.Write([]byte(`{"errors": [{"message": "Field 'badField' doesn't exist"}]}`))
266+
},
267+
wantErr: true,
268+
},
269+
{
270+
name: "successful response with pr data",
271+
serverHandler: func(w http.ResponseWriter, r *http.Request) {
272+
w.WriteHeader(http.StatusOK)
273+
w.Write([]byte(`{
274+
"data": {
275+
"repository": {
276+
"pullRequest": {
277+
"id": "PR_123",
278+
"number": 1,
279+
"title": "Test PR",
280+
"body": "Test body",
281+
"state": "OPEN",
282+
"mergeable": "MERGEABLE",
283+
"mergeStateStatus": "CLEAN",
284+
"authorAssociation": "OWNER",
285+
"isDraft": false,
286+
"additions": 10,
287+
"deletions": 5,
288+
"changedFiles": 2,
289+
"createdAt": "2024-01-01T00:00:00Z",
290+
"updatedAt": "2024-01-02T00:00:00Z",
291+
"author": {"login": "testuser"},
292+
"assignees": {"nodes": []},
293+
"labels": {"nodes": []},
294+
"reviewRequests": {"nodes": []},
295+
"baseRef": {
296+
"name": "main",
297+
"target": {"oid": "abc123"}
298+
},
299+
"headRef": {
300+
"name": "feature",
301+
"target": {"oid": "def456"}
302+
},
303+
"reviews": {"nodes": []},
304+
"timelineItems": {"nodes": [], "pageInfo": {"hasNextPage": false}},
305+
"latestReviews": {"nodes": []}
306+
}
307+
},
308+
"rateLimit": {
309+
"cost": 1,
310+
"remaining": 5000,
311+
"limit": 5000,
312+
"resetAt": "2024-01-01T01:00:00Z"
313+
}
314+
}
315+
}`))
316+
},
317+
wantErr: false,
318+
},
319+
}
320+
321+
for _, tt := range tests {
322+
t.Run(tt.name, func(t *testing.T) {
323+
server := httptest.NewServer(tt.serverHandler)
324+
defer server.Close()
325+
326+
platform := NewTestPlatform("test-token", server.URL)
327+
328+
_, err := platform.executeGraphQL(context.Background(), "owner", "repo", 1)
329+
330+
if tt.wantErr && err == nil {
331+
t.Error("Expected error but got none")
332+
}
333+
if !tt.wantErr && err != nil {
334+
t.Errorf("Unexpected error: %v", err)
335+
}
336+
})
337+
}
338+
}
339+
340+
func TestTruncateSHA(t *testing.T) {
341+
tests := []struct {
342+
name string
343+
sha string
344+
wantSHA string
345+
}{
346+
{
347+
name: "long sha",
348+
sha: "1234567890abcdef",
349+
wantSHA: "1234567",
350+
},
351+
{
352+
name: "short sha",
353+
sha: "12345",
354+
wantSHA: "12345",
355+
},
356+
{
357+
name: "exactly 7 chars",
358+
sha: "1234567",
359+
wantSHA: "1234567",
360+
},
361+
{
362+
name: "empty sha",
363+
sha: "",
364+
wantSHA: "",
365+
},
366+
}
367+
368+
for _, tt := range tests {
369+
t.Run(tt.name, func(t *testing.T) {
370+
result := truncateSHA(tt.sha)
371+
if result != tt.wantSHA {
372+
t.Errorf("Expected %q, got %q", tt.wantSHA, result)
373+
}
374+
})
375+
}
376+
}

0 commit comments

Comments
 (0)