Skip to content

Commit 0a089bc

Browse files
authored
🌱 Added test cases for list.go and github.go (#11937)
* Added test cases for list.go and github.go * Linting issues fixed * mock github and fix test cases * fixing broken test * PR Review changes * PR review changes
1 parent 15a4355 commit 0a089bc

File tree

5 files changed

+301
-1
lines changed

5 files changed

+301
-1
lines changed

hack/tools/release/notes/github.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ type githubClient struct {
3535
repo string
3636
}
3737

38+
// to allow for mocking in tests.
39+
type githubClientInterface interface {
40+
getDiffAllCommits(base, head string) (*githubDiff, error)
41+
getRef(ref string) (githubRef, error)
42+
getTag(tagSHA string) (githubTag, error)
43+
getCommit(sha string) (githubCommit, error)
44+
listMergedPRs(after, before time.Time, baseBranches ...string) ([]githubPR, error)
45+
}
46+
47+
// Ensure githubClient implements githubClientInterface.
48+
var _ githubClientInterface = (*githubClient)(nil)
49+
3850
// githubDiff is the API response for the "compare" endpoint.
3951
type githubDiff struct {
4052
// MergeBaseCommit points to most recent common ancestor between two references.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//go:build tools
2+
// +build tools
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package main
21+
22+
import (
23+
"fmt"
24+
"time"
25+
)
26+
27+
// mockGithubClient is a mock implementation of githubClientInterface for testing.
28+
type mockGithubClient struct {
29+
// Mock responses
30+
diffResponse *githubDiff
31+
refResponse githubRef
32+
tagResponse githubTag
33+
commitResponse githubCommit
34+
prsResponse []githubPR
35+
36+
// Mock errors
37+
diffError error
38+
refError error
39+
tagError error
40+
commitError error
41+
prsError error
42+
}
43+
44+
// Ensure mockGithubClient implements githubClientInterface.
45+
var _ githubClientInterface = (*mockGithubClient)(nil)
46+
47+
func (m *mockGithubClient) getDiffAllCommits(_, _ string) (*githubDiff, error) {
48+
if m.diffError != nil {
49+
return nil, m.diffError
50+
}
51+
return m.diffResponse, nil
52+
}
53+
54+
func (m *mockGithubClient) getRef(_ string) (githubRef, error) {
55+
if m.refError != nil {
56+
return githubRef{}, m.refError
57+
}
58+
return m.refResponse, nil
59+
}
60+
61+
func (m *mockGithubClient) getTag(_ string) (githubTag, error) {
62+
if m.tagError != nil {
63+
return githubTag{}, m.tagError
64+
}
65+
return m.tagResponse, nil
66+
}
67+
68+
func (m *mockGithubClient) getCommit(_ string) (githubCommit, error) {
69+
if m.commitError != nil {
70+
return githubCommit{}, m.commitError
71+
}
72+
return m.commitResponse, nil
73+
}
74+
75+
func (m *mockGithubClient) listMergedPRs(_, _ time.Time, _ ...string) ([]githubPR, error) {
76+
if m.prsError != nil {
77+
return nil, m.prsError
78+
}
79+
return m.prsResponse, nil
80+
}
81+
82+
// newMockGithubClient creates a new mock client with default responses.
83+
func newMockGithubClient() *mockGithubClient {
84+
return &mockGithubClient{
85+
diffResponse: &githubDiff{
86+
MergeBaseCommit: githubCommitNode{
87+
Commit: githubCommit{
88+
Message: "Merge commit",
89+
Committer: githubCommitter{
90+
Date: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
91+
},
92+
},
93+
},
94+
Commits: []githubCommitNode{
95+
{
96+
Commit: githubCommit{
97+
Message: "Merge pull request #1234 from test/branch",
98+
},
99+
},
100+
},
101+
},
102+
refResponse: githubRef{
103+
Object: githubObject{
104+
ObjectType: commitType,
105+
SHA: "abc123",
106+
},
107+
},
108+
tagResponse: githubTag{
109+
Object: githubObject{
110+
ObjectType: tagType,
111+
SHA: "def456",
112+
},
113+
},
114+
commitResponse: githubCommit{
115+
Message: "Test commit",
116+
Committer: githubCommitter{
117+
Date: time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC),
118+
},
119+
},
120+
prsResponse: []githubPR{
121+
{
122+
Number: 1234,
123+
Title: "Test PR",
124+
Labels: []githubLabel{
125+
{Name: "area/testing"},
126+
},
127+
User: githubUser{
128+
Login: "testuser",
129+
},
130+
},
131+
},
132+
}
133+
}
134+
135+
// newMockGithubClientWithError creates a mock client that returns an error for specific operations.
136+
func newMockGithubClientWithError(operation string, err error) *mockGithubClient {
137+
mock := newMockGithubClient()
138+
switch operation {
139+
case "diff":
140+
mock.diffError = err
141+
case "ref":
142+
mock.refError = err
143+
case "tag":
144+
mock.tagError = err
145+
case "commit":
146+
mock.commitError = err
147+
case "prs":
148+
mock.prsError = err
149+
}
150+
return mock
151+
}
152+
153+
// newMockGithubClientForInvalidRef creates a mock client that simulates invalid ref scenarios.
154+
func newMockGithubClientForInvalidRef() *mockGithubClient {
155+
mock := newMockGithubClient()
156+
mock.diffError = fmt.Errorf("invalid ref")
157+
return mock
158+
}

hack/tools/release/notes/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030

3131
// githubFromToPRLister lists PRs from GitHub contained between two refs.
3232
type githubFromToPRLister struct {
33-
client *githubClient
33+
client githubClientInterface
3434
fromRef, toRef ref
3535
// branch is optional. It helps optimize the PR query by restricting
3636
// the results to PRs merged in the selected branch and in main

hack/tools/release/notes/list_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,22 @@ limitations under the License.
2020
package main
2121

2222
import (
23+
"fmt"
2324
"testing"
2425

2526
. "github.com/onsi/gomega"
2627
)
2728

29+
// newGithubFromToPRListerWithClient is a helper function for testing purposes.
30+
// It creates a new githubFromToPRLister with the given client, fromRef, toRef and branch.
31+
func newGithubFromToPRListerWithClient(client githubClientInterface, fromRef, toRef ref, branch string) *githubFromToPRLister {
32+
return &githubFromToPRLister{
33+
client: client,
34+
fromRef: fromRef,
35+
toRef: toRef,
36+
branch: branch,
37+
}
38+
}
2839
func Test_buildSetOfPRNumbers(t *testing.T) {
2940
tests := []struct {
3041
name string
@@ -65,3 +76,121 @@ func Test_buildSetOfPRNumbers(t *testing.T) {
6576
})
6677
}
6778
}
79+
80+
func Test_githubFromToPRLister_listPRs(t *testing.T) {
81+
tests := []struct {
82+
name string
83+
lister *githubFromToPRLister
84+
args ref
85+
want []pr
86+
wantErr bool
87+
}{
88+
{
89+
name: "Successful PR Listing",
90+
lister: newGithubFromToPRListerWithClient(
91+
newMockGithubClient(),
92+
ref{reType: "tags", value: "v0.26.0"},
93+
ref{reType: "tags", value: "v0.27.0"},
94+
"main",
95+
),
96+
args: ref{
97+
reType: "tags",
98+
value: "v0.26.0",
99+
},
100+
want: []pr{
101+
{
102+
number: 1234,
103+
title: "Test PR",
104+
labels: []string{"area/testing"},
105+
user: "testuser",
106+
},
107+
},
108+
wantErr: false,
109+
},
110+
{
111+
name: "Setting previousReleaseRef.value blank - should use toRef and fromRef from fields",
112+
lister: newGithubFromToPRListerWithClient(
113+
newMockGithubClient(),
114+
ref{reType: "tags", value: "v0.26.0"},
115+
ref{reType: "tags", value: "v0.27.0"},
116+
"main",
117+
),
118+
args: ref{
119+
reType: "tags",
120+
value: "",
121+
},
122+
want: []pr{
123+
{
124+
number: 1234,
125+
title: "Test PR",
126+
labels: []string{"area/testing"},
127+
user: "testuser",
128+
},
129+
},
130+
wantErr: false,
131+
},
132+
{
133+
name: "Create PR List when fromRef is not set",
134+
lister: newGithubFromToPRListerWithClient(
135+
newMockGithubClient(),
136+
ref{reType: "tags", value: ""},
137+
ref{reType: "tags", value: "v0.27.0"},
138+
"main",
139+
),
140+
args: ref{
141+
reType: "tags",
142+
value: "v0.26.0",
143+
},
144+
want: []pr{
145+
{
146+
number: 1234,
147+
title: "Test PR",
148+
labels: []string{"area/testing"},
149+
user: "testuser",
150+
},
151+
},
152+
wantErr: false,
153+
},
154+
{
155+
name: "Fail when previousReleaseRef.value is set to invalid",
156+
lister: newGithubFromToPRListerWithClient(
157+
newMockGithubClientForInvalidRef(),
158+
ref{reType: "tags", value: "v0.26.0"},
159+
ref{reType: "tags", value: "v0.27.0"},
160+
"main",
161+
),
162+
args: ref{
163+
reType: "tags",
164+
value: "invalid",
165+
},
166+
want: nil,
167+
wantErr: true,
168+
},
169+
{
170+
name: "Fail when toRef and previousReleaseRef set blank",
171+
lister: newGithubFromToPRListerWithClient(
172+
newMockGithubClientWithError("diff", fmt.Errorf("invalid ref")),
173+
ref{reType: "tags", value: "v0.26.0"},
174+
ref{reType: "tags", value: ""},
175+
"main",
176+
),
177+
args: ref{
178+
reType: "tags",
179+
value: "",
180+
},
181+
want: nil,
182+
wantErr: true,
183+
},
184+
}
185+
for _, tt := range tests {
186+
t.Run(tt.name, func(t *testing.T) {
187+
g := NewWithT(t)
188+
got, err := tt.lister.listPRs(tt.args)
189+
if (err != nil) != tt.wantErr {
190+
t.Errorf("githubFromToPRLister.listPRs() error = %v, wantErr %v", err, tt.wantErr)
191+
return
192+
}
193+
g.Expect(got).To(Equal(tt.want))
194+
})
195+
}
196+
}

hack/tools/release/notes/process.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ var (
4848
"api": "API",
4949
"machinepool": "MachinePool",
5050
"clustercachetracker": "ClusterCacheTracker",
51+
"clustercache": "ClusterCache",
5152
"clusterclass": "ClusterClass",
5253
"testing": "Testing",
5354
"release": "Release",

0 commit comments

Comments
 (0)