Skip to content

Commit 08f0c84

Browse files
freeznetclaude
andcommitted
feat(mcp): add E2E testing with GitHub Actions
Add comprehensive E2E testing infrastructure for Pulsar integration: - Pulsar topic CRUD operations (list, get, create, delete, partitioned) - MCP server connectivity and readiness checks - GitHub Actions workflow with native service containers - Race detection for concurrent testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <[email protected]>
1 parent f8fd16f commit 08f0c84

File tree

6 files changed

+943
-0
lines changed

6 files changed

+943
-0
lines changed

.github/workflows/e2e.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2025 StreamNative
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: E2E Tests
16+
17+
on:
18+
push:
19+
branches: [main, "release/**"]
20+
pull_request:
21+
branches: [main, "release/**"]
22+
23+
permissions:
24+
contents: read
25+
26+
jobs:
27+
pulsar-e2e:
28+
runs-on: ubuntu-latest
29+
30+
services:
31+
pulsar:
32+
image: apachepulsar/pulsar:3.3.0
33+
ports:
34+
- 6650:6650
35+
- 8080:8080
36+
options: >-
37+
--health-cmd "curl -f http://localhost:8080/admin/v2/clusters"
38+
--health-interval 10s
39+
--health-timeout 5s
40+
--health-retries 5
41+
42+
steps:
43+
- name: Check out code
44+
uses: actions/checkout@v4
45+
46+
- name: Set up Go
47+
uses: actions/setup-go@v5
48+
with:
49+
go-version-file: "go.mod"
50+
51+
- name: Download dependencies
52+
run: go mod download
53+
54+
- name: Run E2E tests
55+
run: go test -v -tags=e2e -race ./pkg/mcp/e2e/...
56+
env:
57+
PULSAR_ADMIN_URL: http://localhost:8080
58+
PULSAR_SERVICE_URL: pulsar://localhost:6650

pkg/mcp/e2e/e2e_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2025 StreamNative
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build e2e
16+
17+
package e2e_test
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"os"
23+
"testing"
24+
"time"
25+
26+
"github.com/modelcontextprotocol/go-sdk/mcp"
27+
"github.com/streamnative/streamnative-mcp-server/pkg/mcp/internal/testutil"
28+
"github.com/stretchr/testify/require"
29+
)
30+
31+
// setupPulsarE2EServer sets up a Pulsar E2E test server.
32+
// It uses environment variables for configuration or falls back to defaults.
33+
func setupPulsarE2EServer(t *testing.T) *testutil.PulsarE2ETestServer {
34+
adminURL := os.Getenv("PULSAR_ADMIN_URL")
35+
if adminURL == "" {
36+
adminURL = "http://localhost:8080"
37+
}
38+
39+
serviceURL := os.Getenv("PULSAR_SERVICE_URL")
40+
if serviceURL == "" {
41+
serviceURL = "pulsar://localhost:6650"
42+
}
43+
44+
server := testutil.NewPulsarE2ETestServer(t, adminURL, serviceURL)
45+
46+
return server
47+
}
48+
49+
// TestE2EPulsarConnection verifies that we can connect to Pulsar.
50+
func TestE2EPulsarConnection(t *testing.T) {
51+
t.Parallel()
52+
server := setupPulsarE2EServer(t)
53+
ctx := context.Background()
54+
55+
// Verify connection by listing tools
56+
response, err := server.Session.ListTools(ctx, &mcp.ListToolsParams{})
57+
require.NoError(t, err, "failed to list tools")
58+
require.NotNil(t, response)
59+
require.NotEmpty(t, response.Tools, "expected at least one tool")
60+
61+
// Verify pulsar_admin_topic tool is registered
62+
found := false
63+
for _, tool := range response.Tools {
64+
if tool.Name == "pulsar_admin_topic" {
65+
found = true
66+
break
67+
}
68+
}
69+
require.True(t, found, "pulsar_admin_topic tool not found")
70+
}
71+
72+
// TestE2EPulsarWaitForReady tests the WaitForReady helper.
73+
func TestE2EPulsarWaitForReady(t *testing.T) {
74+
t.Parallel()
75+
adminURL := os.Getenv("PULSAR_ADMIN_URL")
76+
if adminURL == "" {
77+
adminURL = "http://localhost:8080"
78+
}
79+
80+
serviceURL := os.Getenv("PULSAR_SERVICE_URL")
81+
if serviceURL == "" {
82+
serviceURL = "pulsar://localhost:6650"
83+
}
84+
85+
helper, err := testutil.NewPulsarTestHelper(adminURL, serviceURL)
86+
require.NoError(t, err, "failed to create pulsar helper")
87+
t.Cleanup(func() { helper.Close() })
88+
89+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
90+
defer cancel()
91+
92+
err = helper.WaitForReady(ctx)
93+
require.NoError(t, err, "pulsar not ready")
94+
}
95+
96+
// cleanupTestTopic is a helper to cleanup a test topic.
97+
func cleanupTestTopic(t *testing.T, helper *testutil.PulsarTestHelper, topic string) {
98+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
99+
defer cancel()
100+
101+
if err := helper.CleanupTopic(ctx, topic); err != nil {
102+
t.Logf("Warning: failed to cleanup topic %s: %v", topic, err)
103+
}
104+
}
105+
106+
// generateTestTopicName generates a unique test topic name.
107+
func generateTestTopicName() string {
108+
return testutil.GenerateTestTopicName(fmt.Sprintf("test-%d", time.Now().UnixNano()))
109+
}

0 commit comments

Comments
 (0)