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

Commit251a447

Browse files
committed
Add first conformance test (fails)
1 parent001a665 commit251a447

File tree

3 files changed

+430
-14
lines changed

3 files changed

+430
-14
lines changed

‎conformance/conformance_test.go

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
package conformance_test
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"os"
10+
"strings"
11+
"testing"
12+
13+
"github.com/docker/docker/api/types/container"
14+
"github.com/docker/docker/api/types/network"
15+
"github.com/docker/docker/client"
16+
"github.com/docker/docker/pkg/stdcopy"
17+
"github.com/google/go-cmp/cmp"
18+
"github.com/stretchr/testify/require"
19+
)
20+
21+
typemaintainerstring
22+
23+
const (
24+
anthropicmaintainer="anthropic"
25+
githubmaintainer="github"
26+
)
27+
28+
typetestLogWriterstruct {
29+
t*testing.T
30+
}
31+
32+
func (wtestLogWriter)Write(p []byte) (nint,errerror) {
33+
w.t.Log(string(p))
34+
returnlen(p),nil
35+
}
36+
37+
funcstart(t*testing.T,mmaintainer)server {
38+
varimagestring
39+
ifm==github {
40+
image="github/github-mcp-server"
41+
}else {
42+
image="mcp/github"
43+
}
44+
45+
ctx:=context.Background()
46+
dockerClient,err:=client.NewClientWithOpts(client.FromEnv,client.WithAPIVersionNegotiation())
47+
require.NoError(t,err)
48+
49+
containerCfg:=&container.Config{
50+
OpenStdin:true,
51+
AttachStdin:true,
52+
AttachStdout:true,
53+
AttachStderr:true,
54+
Env: []string{
55+
fmt.Sprintf("GITHUB_PERSONAL_ACCESS_TOKEN=%s",os.Getenv("GITHUB_PERSONAL_ACCESS_TOKEN")),
56+
},
57+
Image:image,
58+
}
59+
60+
resp,err:=dockerClient.ContainerCreate(
61+
ctx,
62+
containerCfg,
63+
&container.HostConfig{},
64+
&network.NetworkingConfig{},
65+
nil,
66+
"")
67+
require.NoError(t,err)
68+
69+
t.Cleanup(func() {
70+
require.NoError(t,dockerClient.ContainerRemove(ctx,resp.ID, container.RemoveOptions{Force:true}))
71+
})
72+
73+
hijackedResponse,err:=dockerClient.ContainerAttach(ctx,resp.ID, container.AttachOptions{
74+
Stream:true,
75+
Stdin:true,
76+
Stdout:true,
77+
Stderr:true,
78+
})
79+
require.NoError(t,err)
80+
t.Cleanup(func() {hijackedResponse.Close() })
81+
82+
require.NoError(t,dockerClient.ContainerStart(ctx,resp.ID, container.StartOptions{}))
83+
84+
serverStart:=make(chanserverStartResult)
85+
gofunc() {
86+
prOut,pwOut:=io.Pipe()
87+
prErr,pwErr:=io.Pipe()
88+
89+
gofunc() {
90+
// Ignore error, we should be done?
91+
// TODO: maybe check for use of closed network connection specifically
92+
_,_=stdcopy.StdCopy(pwOut,pwErr,hijackedResponse.Reader)
93+
pwOut.Close()
94+
pwErr.Close()
95+
}()
96+
97+
bufferedStderr:=bufio.NewReader(prErr)
98+
line,err:=bufferedStderr.ReadString('\n')
99+
iferr!=nil {
100+
serverStart<-serverStartResult{err:err}
101+
}
102+
103+
ifstrings.TrimSpace(line)!="GitHub MCP Server running on stdio" {
104+
serverStart<-serverStartResult{
105+
err:fmt.Errorf("unexpected server output: %s",line),
106+
}
107+
return
108+
}
109+
110+
serverStart<-serverStartResult{
111+
server:server{
112+
m:m,
113+
log:testLogWriter{t},
114+
stdin:hijackedResponse.Conn,
115+
stdout:bufio.NewReader(prOut),
116+
},
117+
}
118+
}()
119+
120+
t.Logf("waiting for %s server to start...",m)
121+
serveResult:=<-serverStart
122+
require.NoError(t,serveResult.err,"expected the server to start successfully")
123+
124+
returnserveResult.server
125+
}
126+
127+
funcTestCapabilities(t*testing.T) {
128+
githubServer:=start(t,github)
129+
anthropicServer:=start(t,anthropic)
130+
131+
req:=newInitializeRequest(
132+
initializeRequestParams{
133+
ProtocolVersion:"2024-11-05",
134+
Capabilities:clientCapabilities{},
135+
ClientInfo:clientInfo{
136+
Name:"ConformanceTest",
137+
Version:"0.0.1",
138+
},
139+
},
140+
)
141+
142+
require.NoError(t,githubServer.send(req))
143+
144+
varghInitializeResponseinitializeResponse
145+
require.NoError(t,githubServer.receive(&ghInitializeResponse))
146+
147+
require.NoError(t,anthropicServer.send(req))
148+
149+
varanthropicInitializeResponseinitializeResponse
150+
require.NoError(t,anthropicServer.receive(&anthropicInitializeResponse))
151+
152+
ifdiff:=cmp.Diff(ghInitializeResponse.Result.Capabilities,anthropicInitializeResponse.Result.Capabilities);diff!="" {
153+
t.Errorf("unexpected capability differential: %s",diff)
154+
}
155+
}
156+
157+
typeserverStartResultstruct {
158+
serverserver
159+
errerror
160+
}
161+
162+
typeserverstruct {
163+
mmaintainer
164+
log io.Writer
165+
166+
stdin io.Writer
167+
stdout*bufio.Reader
168+
}
169+
170+
func (sserver)send(reqrequest)error {
171+
b,err:=req.marshal()
172+
iferr!=nil {
173+
returnerr
174+
}
175+
176+
fmt.Fprintf(s.log,"sending %s: %s\n",s.m,string(b))
177+
178+
n,err:=s.stdin.Write(append(b,'\n'))
179+
iferr!=nil {
180+
returnerr
181+
}
182+
183+
ifn!=len(b)+1 {
184+
returnfmt.Errorf("wrote %d bytes, expected %d",n,len(b)+1)
185+
}
186+
187+
returnnil
188+
}
189+
190+
func (sserver)receive(resresponse)error {
191+
line,err:=s.stdout.ReadBytes('\n')
192+
iferr!=nil {
193+
iferr==io.EOF {
194+
returnfmt.Errorf("EOF after reading %s",string(line))
195+
}
196+
returnerr
197+
}
198+
199+
fmt.Fprintf(s.log,"received from %s: %s\n",s.m,string(line))
200+
201+
returnres.unmarshal(line)
202+
}
203+
204+
typejsonRPRCRequest[paramsany]struct {
205+
JSONRPCstring`json:"jsonrpc"`
206+
IDint`json:"id"`
207+
Methodstring`json:"method"`
208+
Paramsparams`json:"params"`
209+
}
210+
211+
typejsonRPRCResponse[resultany]struct {
212+
JSONRPCstring`json:"jsonrpc"`
213+
IDint`json:"id"`
214+
Methodstring`json:"method"`
215+
Resultresult`json:"result"`
216+
}
217+
218+
typerequestinterface {
219+
marshal() ([]byte,error)
220+
}
221+
222+
typeresponseinterface {
223+
unmarshal([]byte)error
224+
}
225+
226+
funcnewInitializeRequest(paramsinitializeRequestParams)initializeRequest {
227+
returninitializeRequest{
228+
jsonRPRCRequest:jsonRPRCRequest[initializeRequestParams]{
229+
JSONRPC:"2.0",
230+
ID:1,
231+
Method:"initialize",
232+
Params:params,
233+
},
234+
}
235+
}
236+
237+
typeinitializeRequeststruct {
238+
jsonRPRCRequest[initializeRequestParams]
239+
}
240+
241+
func (rinitializeRequest)marshal() ([]byte,error) {
242+
returnjson.Marshal(r)
243+
}
244+
245+
typeinitializeRequestParamsstruct {
246+
ProtocolVersionstring`json:"protocolVersion"`
247+
CapabilitiesclientCapabilities`json:"capabilities"`
248+
ClientInfoclientInfo`json:"clientInfo"`
249+
}
250+
251+
typeclientCapabilitiesstruct{}// don't actually care about any of these right now
252+
253+
typeclientInfostruct {
254+
Namestring`json:"name"`
255+
Versionstring`json:"version"`
256+
}
257+
258+
typeinitializeResponsestruct {
259+
jsonRPRCResponse[initializeResult]
260+
}
261+
262+
func (r*initializeResponse)unmarshal(b []byte)error {
263+
returnjson.Unmarshal(b,r)
264+
}
265+
266+
typeinitializeResultstruct {
267+
ProtocolVersionstring`json:"protocolVersion"`
268+
CapabilitiesserverCapabilities`json:"capabilities"`
269+
ServerInfoserverInfo`json:"serverInfo"`
270+
}
271+
272+
typeserverCapabilitiesstruct {
273+
Loggingstruct{}`json:"logging"`
274+
Promptsstruct {
275+
ListChangedbool`json:"listChanged"`
276+
}`json:"prompts"`
277+
Resourcesstruct {
278+
Subscribebool`json:"subscribe"`
279+
ListChangedbool`json:"listChanged"`
280+
}`json:"resources"`
281+
Toolsstruct {
282+
ListChangedbool`json:"listChanged"`
283+
}`json:"tools"`
284+
}
285+
286+
typeserverInfostruct {
287+
Namestring`json:"name"`
288+
Versionstring`json:"version"`
289+
}

‎go.mod

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,45 @@ go 1.23.7
44

55
require (
66
github.com/aws/smithy-gov1.22.3
7+
github.com/docker/dockerv28.0.4+incompatible
8+
github.com/google/go-cmpv0.7.0
79
github.com/google/go-github/v69v69.2.0
810
github.com/mark3labs/mcp-gov0.14.1
911
github.com/migueleliasweb/go-github-mockv1.1.0
1012
github.com/sirupsen/logrusv1.9.3
1113
github.com/spf13/cobrav1.9.1
1214
github.com/spf13/viperv1.19.0
13-
github.com/stretchr/testifyv1.9.0
15+
github.com/stretchr/testifyv1.10.0
1416
golang.org/x/expv0.0.0-20230905200255-921286631fa9
1517
)
1618

1719
require (
20+
github.com/Microsoft/go-winiov0.6.2// indirect
21+
github.com/containerd/logv0.1.0// indirect
1822
github.com/davecgh/go-spewv1.1.2-0.20180830191138-d8f796af33cc// indirect
23+
github.com/distribution/referencev0.6.0// indirect
24+
github.com/docker/go-connectionsv0.5.0// indirect
25+
github.com/docker/go-unitsv0.5.0// indirect
26+
github.com/felixge/httpsnoopv1.0.4// indirect
1927
github.com/fsnotify/fsnotifyv1.7.0// indirect
28+
github.com/go-logr/logrv1.4.2// indirect
29+
github.com/go-logr/stdrv1.2.2// indirect
30+
github.com/gogo/protobufv1.3.2// indirect
2031
github.com/google/go-github/v64v64.0.0// indirect
2132
github.com/google/go-querystringv1.1.0// indirect
2233
github.com/google/uuidv1.6.0// indirect
2334
github.com/gorilla/muxv1.8.0// indirect
2435
github.com/hashicorp/hclv1.0.0// indirect
2536
github.com/inconshreveable/mousetrapv1.1.0// indirect
26-
github.com/magiconair/propertiesv1.8.7// indirect
37+
github.com/magiconair/propertiesv1.8.9// indirect
2738
github.com/mitchellh/mapstructurev1.5.0// indirect
39+
github.com/moby/docker-image-specv1.3.1// indirect
40+
github.com/moby/termv0.5.0// indirect
41+
github.com/morikuni/aecv1.0.0// indirect
42+
github.com/opencontainers/go-digestv1.0.0// indirect
43+
github.com/opencontainers/image-specv1.1.1// indirect
2844
github.com/pelletier/go-toml/v2v2.2.2// indirect
45+
github.com/pkg/errorsv0.9.1// indirect
2946
github.com/pmezard/go-difflibv1.0.1-0.20181226105442-5d4384ee4fb2// indirect
3047
github.com/sagikazarmark/locaferov0.4.0// indirect
3148
github.com/sagikazarmark/slog-shimv0.1.0// indirect
@@ -35,11 +52,22 @@ require (
3552
github.com/spf13/pflagv1.0.6// indirect
3653
github.com/subosito/gotenvv1.6.0// indirect
3754
github.com/yosida95/uritemplate/v3v3.0.2// indirect
55+
go.opentelemetry.io/auto/sdkv1.1.0// indirect
56+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttpv0.49.0// indirect
57+
go.opentelemetry.io/otelv1.35.0// indirect
58+
go.opentelemetry.io/otel/exporters/otlp/otlptracev1.35.0// indirect
59+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttpv1.19.0// indirect
60+
go.opentelemetry.io/otel/metricv1.35.0// indirect
61+
go.opentelemetry.io/otel/sdkv1.35.0// indirect
62+
go.opentelemetry.io/otel/tracev1.35.0// indirect
63+
go.opentelemetry.io/proto/otlpv1.5.0// indirect
3864
go.uber.org/atomicv1.9.0// indirect
3965
go.uber.org/multierrv1.9.0// indirect
40-
golang.org/x/sysv0.28.0// indirect
66+
golang.org/x/sysv0.31.0// indirect
4167
golang.org/x/textv0.21.0// indirect
4268
golang.org/x/timev0.5.0// indirect
69+
google.golang.org/protobufv1.36.5// indirect
4370
gopkg.in/ini.v1v1.67.0// indirect
4471
gopkg.in/yaml.v3v3.0.1// indirect
72+
gotest.tools/v3v3.5.1// indirect
4573
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp