55 "encoding/json"
66 "errors"
77 "fmt"
8+ "net/http"
89 "os"
910 "os/exec"
1011 "strconv"
@@ -23,10 +24,18 @@ import (
2324// Note: make sure you ran `task install` before running this test
2425// ------------------------------------------------------------------------------------------------
2526
27+ const (
28+ MCPServerListen = "localhost:50081"
29+ MCPServerDebug = true
30+ ArgoCDMockListen = "localhost:50084"
31+ ArgoCDMockToken = "secure-token"
32+ ArgoCDMockDebug = true
33+ )
34+
2635func TestServer (t * testing.T ) {
2736
2837 // start the argocd mock server
29- cmd := exec .CommandContext (context .Background (), "argocd-mock" )
38+ cmd := exec .CommandContext (context .Background (), "argocd-mock" , "--listen" , ArgoCDMockListen , "--token" , ArgoCDMockToken , "--debug" , strconv . FormatBool ( ArgoCDMockDebug )) //nolint:gosec // (it's ok to use `strconv.FormatBool` )
3039 cmd .Stdout = os .Stdout
3140 cmd .Stderr = os .Stderr
3241 go func () {
@@ -42,23 +51,17 @@ func TestServer(t *testing.T) {
4251 t .Logf ("killed the Argo CD mock server: %v" , cmd .String ())
4352 }()
4453
45- os .Setenv ("MCP_SERVER_LISTEN" , "localhost:50081" )
46- os .Setenv ("MCP_SERVER_DEBUG" , "true" )
47- os .Setenv ("ARGOCD_SERVER_LISTEN" , "localhost:50084" )
48- os .Setenv ("ARGOCD_SERVER_TOKEN" , "secure-token" )
49- os .Setenv ("ARGOCD_SERVER_DEBUG" , "true" )
50-
5154 testdata := []struct {
5255 name string
5356 init func (* testing.T ) (* mcp.ClientSession , KillMCPServerFunc )
5457 }{
5558 {
5659 name : "stdio" ,
57- init : newStdioSession ("localhost:50081" , true , "http://localhost:50084" , "secure-token" ),
60+ init : newStdioSession (MCPServerListen , MCPServerDebug , "http://" + ArgoCDMockListen , ArgoCDMockToken ),
5861 },
5962 {
6063 name : "http" ,
61- init : newHTTPSession ("localhost:50081" , true , "http://localhost:50084" , "secure-token" ),
64+ init : newHTTPSession (MCPServerListen , MCPServerDebug , "http://" + ArgoCDMockListen , ArgoCDMockToken ),
6265 },
6366 }
6467
@@ -182,11 +185,11 @@ func TestServer(t *testing.T) {
182185 }{
183186 {
184187 name : "stdio" ,
185- init : newStdioSession ("localhost:50081" , true , "http://localhost:50085" , "another-token" ), // invalid URL and token for the Argo CD server
188+ init : newStdioSession (MCPServerListen , MCPServerDebug , "http://localhost:50085" , "another-token" ), // invalid URL and token for the Argo CD server
186189 },
187190 {
188191 name : "http" ,
189- init : newHTTPSession ("localhost:50081" , true , "http://localhost:50085" , "another-token" ), // invalid URL and token for the Argo CD server
192+ init : newHTTPSession (MCPServerListen , MCPServerDebug , "http://localhost:50085" , "another-token" ), // invalid URL and token for the Argo CD server
190193 },
191194 }
192195
@@ -214,10 +217,10 @@ func TestServer(t *testing.T) {
214217
215218type KillMCPServerFunc func ()
216219
217- func newStdioSession (mcpServerListen string , mcpServerDebug bool , argocdURL string , argocdToken string ) func (* testing.T ) (* mcp.ClientSession , KillMCPServerFunc ) {
220+ func newStdioSession (mcpServerListenPort string , mcpServerDebug bool , argocdURL string , argocdToken string ) func (* testing.T ) (* mcp.ClientSession , KillMCPServerFunc ) {
218221 return func (t * testing.T ) (* mcp.ClientSession , KillMCPServerFunc ) {
219222 ctx := context .Background ()
220- cmd := newServerCmd (ctx , "stdio" , mcpServerListen , strconv .FormatBool (mcpServerDebug ), argocdURL , argocdToken )
223+ cmd := newServerCmd (ctx , "stdio" , mcpServerListenPort , strconv .FormatBool (mcpServerDebug ), argocdURL , argocdToken )
221224 cl := mcp .NewClient (& mcp.Implementation {Name : "e2e-test-client" , Version : "v1.0.0" }, nil )
222225 session , err := cl .Connect (ctx , & mcp.CommandTransport {Command : cmd }, nil )
223226 require .NoError (t , err )
@@ -241,13 +244,17 @@ func newHTTPSession(mcpServerListen string, mcpServerDebug bool, argocdURL strin
241244 }
242245 }
243246 }()
244- time .Sleep (5 * time .Second )
247+ cmd .Stderr = os .Stdout
248+ t .Logf ("waiting for the MCP server to start" )
249+ err := waitForMCPServer (mcpServerListen )
250+ require .NoError (t , err , "failed to wait for the MCP server to start" )
251+
245252 cl := mcp .NewClient (& mcp.Implementation {Name : "e2e-test-client" , Version : "v1.0.0" }, nil )
246253 session , err := cl .Connect (ctx , & mcp.StreamableClientTransport {
247254 MaxRetries : 5 ,
248- Endpoint : fmt .Sprintf ("http://%s/mcp" , os . Getenv ( "MCP_SERVER_LISTEN" ) ),
255+ Endpoint : fmt .Sprintf ("http://%s/mcp" , mcpServerListen ),
249256 }, nil )
250- require .NoError (t , err )
257+ require .NoError (t , err , "failed to connect to the MCP server" )
251258 return session , func () {
252259 t .Logf ("killing the MCP server" )
253260 if err := cmd .Process .Kill (); err != nil {
@@ -258,6 +265,26 @@ func newHTTPSession(mcpServerListen string, mcpServerDebug bool, argocdURL strin
258265 }
259266}
260267
268+ func waitForMCPServer (mcpServerListen string ) error {
269+ // wait until the MCP server is ready to accept connections
270+ for {
271+ req , err := http .NewRequestWithContext (context .Background (), "GET" , fmt .Sprintf ("http://%s/health" , mcpServerListen ), nil )
272+ if err != nil {
273+ return fmt .Errorf ("failed to create request: %w" , err )
274+ }
275+ resp , err := http .DefaultClient .Do (req )
276+ if err != nil {
277+ continue
278+ }
279+ defer resp .Body .Close ()
280+ if resp .StatusCode == http .StatusOK {
281+ break
282+ }
283+ time .Sleep (1 * time .Second )
284+ }
285+ return nil
286+ }
287+
261288func newServerCmd (ctx context.Context , transport string , mcpServerListen string , mcpServerDebug string , argocdURL string , argocdToken string ) * exec.Cmd {
262289 return exec .CommandContext (ctx ,
263290 "argocd-mcp-server" ,
0 commit comments