Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitff5e309

Browse files
committed
add initial tests
1 parent09366fa commitff5e309

14 files changed

+3206
-20
lines changed

‎go.mod

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,27 @@ require (
66
github.com/aws/smithy-gov1.22.3
77
github.com/google/go-github/v69v69.2.0
88
github.com/mark3labs/mcp-gov0.11.2
9+
github.com/migueleliasweb/go-github-mockv1.1.0
910
github.com/sirupsen/logrusv1.9.3
1011
github.com/spf13/cobrav1.9.1
1112
github.com/spf13/viperv1.19.0
13+
github.com/stretchr/testifyv1.9.0
1214
golang.org/x/expv0.0.0-20230905200255-921286631fa9
1315
)
1416

1517
require (
18+
github.com/davecgh/go-spewv1.1.2-0.20180830191138-d8f796af33cc// indirect
1619
github.com/fsnotify/fsnotifyv1.7.0// indirect
20+
github.com/google/go-github/v64v64.0.0// indirect
1721
github.com/google/go-querystringv1.1.0// indirect
1822
github.com/google/uuidv1.6.0// indirect
23+
github.com/gorilla/muxv1.8.0// indirect
1924
github.com/hashicorp/hclv1.0.0// indirect
2025
github.com/inconshreveable/mousetrapv1.1.0// indirect
2126
github.com/magiconair/propertiesv1.8.7// indirect
2227
github.com/mitchellh/mapstructurev1.5.0// indirect
2328
github.com/pelletier/go-toml/v2v2.2.2// indirect
29+
github.com/pmezard/go-difflibv1.0.1-0.20181226105442-5d4384ee4fb2// indirect
2430
github.com/sagikazarmark/locaferov0.4.0// indirect
2531
github.com/sagikazarmark/slog-shimv0.1.0// indirect
2632
github.com/sourcegraph/concv0.3.0// indirect
@@ -31,7 +37,8 @@ require (
3137
go.uber.org/atomicv1.9.0// indirect
3238
go.uber.org/multierrv1.9.0// indirect
3339
golang.org/x/sysv0.18.0// indirect
34-
golang.org/x/textv0.14.0// indirect
40+
golang.org/x/textv0.19.0// indirect
41+
golang.org/x/timev0.5.0// indirect
3542
gopkg.in/ini.v1v1.67.0// indirect
3643
gopkg.in/yaml.v3v3.0.1// indirect
3744
)

‎go.sum

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyT
1212
github.com/google/go-cmpv0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
1313
github.com/google/go-cmpv0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
1414
github.com/google/go-cmpv0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
15+
github.com/google/go-github/v64v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg=
16+
github.com/google/go-github/v64v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo=
1517
github.com/google/go-github/v69v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE=
1618
github.com/google/go-github/v69v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM=
1719
github.com/google/go-querystringv1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
1820
github.com/google/go-querystringv1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
1921
github.com/google/uuidv1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
2022
github.com/google/uuidv1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
23+
github.com/gorilla/muxv1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
24+
github.com/gorilla/muxv1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
2125
github.com/hashicorp/hclv1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
2226
github.com/hashicorp/hclv1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
2327
github.com/inconshreveable/mousetrapv1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -30,6 +34,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
3034
github.com/magiconair/propertiesv1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
3135
github.com/mark3labs/mcp-gov0.11.2 h1:mCxWFUTrcXOtJIn9t7F8bxAL8rpE/ZZTTnx3PU/VNdA=
3236
github.com/mark3labs/mcp-gov0.11.2/go.mod h1:cjMlBU0cv/cj9kjlgmRhoJ5JREdS7YX83xeIG9Ko/jE=
37+
github.com/migueleliasweb/go-github-mockv1.1.0 h1:GKaOBPsrPGkAKgtfuWY8MclS1xR6MInkx1SexJucMwE=
38+
github.com/migueleliasweb/go-github-mockv1.1.0/go.mod h1:pYe/XlGs4BGMfRY4vmeixVsODHnVDDhJ9zoi0qzSMHc=
3339
github.com/mitchellh/mapstructurev1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
3440
github.com/mitchellh/mapstructurev1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
3541
github.com/pelletier/go-toml/v2v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
@@ -80,8 +86,10 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqR
8086
golang.org/x/sysv0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8187
golang.org/x/sysv0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
8288
golang.org/x/sysv0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
83-
golang.org/x/textv0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
84-
golang.org/x/textv0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
89+
golang.org/x/textv0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
90+
golang.org/x/textv0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
91+
golang.org/x/timev0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
92+
golang.org/x/timev0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
8593
golang.org/x/xerrorsv0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
8694
gopkg.in/check.v1v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8795
gopkg.in/check.v1v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=

‎pkg/github/code_scanning.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8+
"net/http"
89

910
"github.com/google/go-github/v69/github"
1011
"github.com/mark3labs/mcp-go/mcp"
@@ -38,7 +39,7 @@ func getCodeScanningAlert(client *github.Client) (tool mcp.Tool, handler server.
3839
}
3940
deferfunc() {_=resp.Body.Close() }()
4041

41-
ifresp.StatusCode!=200 {
42+
ifresp.StatusCode!=http.StatusOK {
4243
body,err:=io.ReadAll(resp.Body)
4344
iferr!=nil {
4445
returnnil,fmt.Errorf("failed to read response body: %w",err)
@@ -90,7 +91,7 @@ func listCodeScanningAlerts(client *github.Client) (tool mcp.Tool, handler serve
9091
}
9192
deferfunc() {_=resp.Body.Close() }()
9293

93-
ifresp.StatusCode!=200 {
94+
ifresp.StatusCode!=http.StatusOK {
9495
body,err:=io.ReadAll(resp.Body)
9596
iferr!=nil {
9697
returnnil,fmt.Errorf("failed to read response body: %w",err)

‎pkg/github/code_scanning_test.go

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/google/go-github/v69/github"
10+
"github.com/migueleliasweb/go-github-mock/src/mock"
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
funcTest_GetCodeScanningAlert(t*testing.T) {
16+
// Verify tool definition once
17+
mockClient:=github.NewClient(nil)
18+
tool,_:=getCodeScanningAlert(mockClient)
19+
20+
assert.Equal(t,"get_code_scanning_alert",tool.Name)
21+
assert.NotEmpty(t,tool.Description)
22+
assert.Contains(t,tool.InputSchema.Properties,"owner")
23+
assert.Contains(t,tool.InputSchema.Properties,"repo")
24+
assert.Contains(t,tool.InputSchema.Properties,"alert_number")
25+
assert.ElementsMatch(t,tool.InputSchema.Required, []string{"owner","repo","alert_number"})
26+
27+
// Setup mock alert for success case
28+
mockAlert:=&github.Alert{
29+
Number:github.Ptr(42),
30+
State:github.Ptr("open"),
31+
Rule:&github.Rule{ID:github.Ptr("test-rule"),Description:github.Ptr("Test Rule Description")},
32+
HTMLURL:github.Ptr("https://github.com/owner/repo/security/code-scanning/42"),
33+
}
34+
35+
tests:= []struct {
36+
namestring
37+
mockedClient*http.Client
38+
requestArgsmap[string]interface{}
39+
expectErrorbool
40+
expectedAlert*github.Alert
41+
expectedErrMsgstring
42+
}{
43+
{
44+
name:"successful alert fetch",
45+
mockedClient:mock.NewMockedHTTPClient(
46+
mock.WithRequestMatch(
47+
mock.GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber,
48+
mockAlert,
49+
),
50+
),
51+
requestArgs:map[string]interface{}{
52+
"owner":"owner",
53+
"repo":"repo",
54+
"alert_number":float64(42),
55+
},
56+
expectError:false,
57+
expectedAlert:mockAlert,
58+
},
59+
{
60+
name:"alert fetch fails",
61+
mockedClient:mock.NewMockedHTTPClient(
62+
mock.WithRequestMatchHandler(
63+
mock.GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber,
64+
http.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {
65+
w.WriteHeader(http.StatusNotFound)
66+
_,_=w.Write([]byte(`{"message": "Not Found"}`))
67+
}),
68+
),
69+
),
70+
requestArgs:map[string]interface{}{
71+
"owner":"owner",
72+
"repo":"repo",
73+
"alert_number":float64(9999),
74+
},
75+
expectError:true,
76+
expectedErrMsg:"failed to get alert",
77+
},
78+
}
79+
80+
for_,tc:=rangetests {
81+
t.Run(tc.name,func(t*testing.T) {
82+
// Setup client with mock
83+
client:=github.NewClient(tc.mockedClient)
84+
_,handler:=getCodeScanningAlert(client)
85+
86+
// Create call request
87+
request:=createMCPRequest(tc.requestArgs)
88+
89+
// Call handler
90+
result,err:=handler(context.Background(),request)
91+
92+
// Verify results
93+
iftc.expectError {
94+
require.Error(t,err)
95+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
96+
return
97+
}
98+
99+
require.NoError(t,err)
100+
101+
// Parse the result and get the text content if no error
102+
textContent:=getTextResult(t,result)
103+
104+
// Unmarshal and verify the result
105+
varreturnedAlert github.Alert
106+
err=json.Unmarshal([]byte(textContent.Text),&returnedAlert)
107+
assert.NoError(t,err)
108+
assert.Equal(t,*tc.expectedAlert.Number,*returnedAlert.Number)
109+
assert.Equal(t,*tc.expectedAlert.State,*returnedAlert.State)
110+
assert.Equal(t,*tc.expectedAlert.Rule.ID,*returnedAlert.Rule.ID)
111+
assert.Equal(t,*tc.expectedAlert.HTMLURL,*returnedAlert.HTMLURL)
112+
113+
})
114+
}
115+
}
116+
117+
funcTest_ListCodeScanningAlerts(t*testing.T) {
118+
// Verify tool definition once
119+
mockClient:=github.NewClient(nil)
120+
tool,_:=listCodeScanningAlerts(mockClient)
121+
122+
assert.Equal(t,"list_code_scanning_alerts",tool.Name)
123+
assert.NotEmpty(t,tool.Description)
124+
assert.Contains(t,tool.InputSchema.Properties,"owner")
125+
assert.Contains(t,tool.InputSchema.Properties,"repo")
126+
assert.Contains(t,tool.InputSchema.Properties,"ref")
127+
assert.Contains(t,tool.InputSchema.Properties,"state")
128+
assert.Contains(t,tool.InputSchema.Properties,"severity")
129+
assert.ElementsMatch(t,tool.InputSchema.Required, []string{"owner","repo"})
130+
131+
// Setup mock alerts for success case
132+
mockAlerts:= []*github.Alert{
133+
{
134+
Number:github.Ptr(42),
135+
State:github.Ptr("open"),
136+
Rule:&github.Rule{ID:github.Ptr("test-rule-1"),Description:github.Ptr("Test Rule 1")},
137+
HTMLURL:github.Ptr("https://github.com/owner/repo/security/code-scanning/42"),
138+
},
139+
{
140+
Number:github.Ptr(43),
141+
State:github.Ptr("fixed"),
142+
Rule:&github.Rule{ID:github.Ptr("test-rule-2"),Description:github.Ptr("Test Rule 2")},
143+
HTMLURL:github.Ptr("https://github.com/owner/repo/security/code-scanning/43"),
144+
},
145+
}
146+
147+
tests:= []struct {
148+
namestring
149+
mockedClient*http.Client
150+
requestArgsmap[string]interface{}
151+
expectErrorbool
152+
expectedAlerts []*github.Alert
153+
expectedErrMsgstring
154+
}{
155+
{
156+
name:"successful alerts listing",
157+
mockedClient:mock.NewMockedHTTPClient(
158+
mock.WithRequestMatch(
159+
mock.GetReposCodeScanningAlertsByOwnerByRepo,
160+
mockAlerts,
161+
),
162+
),
163+
requestArgs:map[string]interface{}{
164+
"owner":"owner",
165+
"repo":"repo",
166+
"ref":"main",
167+
"state":"open",
168+
"severity":"high",
169+
},
170+
expectError:false,
171+
expectedAlerts:mockAlerts,
172+
},
173+
{
174+
name:"alerts listing fails",
175+
mockedClient:mock.NewMockedHTTPClient(
176+
mock.WithRequestMatchHandler(
177+
mock.GetReposCodeScanningAlertsByOwnerByRepo,
178+
http.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {
179+
w.WriteHeader(http.StatusUnauthorized)
180+
_,_=w.Write([]byte(`{"message": "Unauthorized access"}`))
181+
}),
182+
),
183+
),
184+
requestArgs:map[string]interface{}{
185+
"owner":"owner",
186+
"repo":"repo",
187+
},
188+
expectError:true,
189+
expectedErrMsg:"failed to list alerts",
190+
},
191+
}
192+
193+
for_,tc:=rangetests {
194+
t.Run(tc.name,func(t*testing.T) {
195+
// Setup client with mock
196+
client:=github.NewClient(tc.mockedClient)
197+
_,handler:=listCodeScanningAlerts(client)
198+
199+
// Create call request
200+
request:=createMCPRequest(tc.requestArgs)
201+
202+
// Call handler
203+
result,err:=handler(context.Background(),request)
204+
205+
// Verify results
206+
iftc.expectError {
207+
require.Error(t,err)
208+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
209+
return
210+
}
211+
212+
require.NoError(t,err)
213+
214+
// Parse the result and get the text content if no error
215+
textContent:=getTextResult(t,result)
216+
217+
// Unmarshal and verify the result
218+
varreturnedAlerts []*github.Alert
219+
err=json.Unmarshal([]byte(textContent.Text),&returnedAlerts)
220+
assert.NoError(t,err)
221+
assert.Len(t,returnedAlerts,len(tc.expectedAlerts))
222+
fori,alert:=rangereturnedAlerts {
223+
assert.Equal(t,*tc.expectedAlerts[i].Number,*alert.Number)
224+
assert.Equal(t,*tc.expectedAlerts[i].State,*alert.State)
225+
assert.Equal(t,*tc.expectedAlerts[i].Rule.ID,*alert.Rule.ID)
226+
assert.Equal(t,*tc.expectedAlerts[i].HTMLURL,*alert.HTMLURL)
227+
}
228+
})
229+
}
230+
}

‎pkg/github/helper_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package github
2+
3+
import (
4+
"encoding/json"
5+
"github.com/stretchr/testify/assert"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/mark3labs/mcp-go/mcp"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
// mockResponse is a helper function to create a mock HTTP response handler
14+
// that returns a specified status code and marshalled body.
15+
funcmockResponse(t*testing.T,codeint,bodyinterface{}) http.HandlerFunc {
16+
t.Helper()
17+
returnfunc(w http.ResponseWriter,r*http.Request) {
18+
w.WriteHeader(code)
19+
b,err:=json.Marshal(body)
20+
require.NoError(t,err)
21+
_,_=w.Write(b)
22+
}
23+
}
24+
25+
// createMCPRequest is a helper function to create a MCP request with the given arguments.
26+
funccreateMCPRequest(argsmap[string]interface{}) mcp.CallToolRequest {
27+
return mcp.CallToolRequest{
28+
Params:struct {
29+
Namestring`json:"name"`
30+
Argumentsmap[string]interface{}`json:"arguments,omitempty"`
31+
Meta*struct {
32+
ProgressToken mcp.ProgressToken`json:"progressToken,omitempty"`
33+
}`json:"_meta,omitempty"`
34+
}{
35+
Arguments:args,
36+
},
37+
}
38+
}
39+
40+
// getTextResult is a helper function that returns a text result from a tool call.
41+
funcgetTextResult(t*testing.T,result*mcp.CallToolResult) mcp.TextContent {
42+
t.Helper()
43+
assert.NotNil(t,result)
44+
require.Len(t,result.Content,1)
45+
require.IsType(t, mcp.TextContent{},result.Content[0])
46+
textContent:=result.Content[0].(mcp.TextContent)
47+
assert.Equal(t,"text",textContent.Type)
48+
returntextContent
49+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp