test(mcp): integration scaffold — 14 scenarios per spec §8.2

- Matrix dispatcher with 14 sub-test stubs
- Suite struct with setup/cleanup lifecycle
- All sub-tests start as t.Skip stubs; filled in K2-K5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-08 13:11:04 +08:00
parent 0644fc9b3b
commit f2ed098f32
+129
View File
@@ -0,0 +1,129 @@
//go:build integration
// mcp_integration_test.go — through-stack integration matrix for the MCP module
// (spec §8.2, 14 scenarios).
//
// SCOPE: This file lays out the matrix of 14 scenarios as a scaffold + sub-tests.
// The suite wiring, helpers, and actual test implementations will be added in K2-K5.
//
// Coverage map (scenario ↔ implementation batch):
//
// Scenario Batch Description
// ----------------------------- ------ ------------------------------------------
// StreamableHTTP_FullFlow K2 StreamableHTTP transport end-to-end
// LegacySSE_FullFlow K2 SSE transport end-to-end
// BearerVsQueryToken K2 Auth via header vs query param
// MCPSDKVersionNegotiation K2 Protocol version negotiation
// ScopeViolation_Tool K3 Token scope restricts tool access
// ScopeViolation_Project K3 Token scope restricts project access
// VisibilityRespect K3 Project visibility enforced
// WriteToolAudit K3 Write tools produce audit records
// RateLimit_PerToken K4 Per-token rate limiting
// ACPSession_TokenLifecycle K4 ACP session tokens created/revoked
// StartupReaper K4 Expired tokens cleaned on startup
// PromptsList_FromTemplates K5 Prompts listed from templates
// ResourceRead_NotFound K5 Resource read returns not-found
// ResourceList_ScopeFilter K5 Resources filtered by scope
//
// Build/run:
// go test -count=1 -tags=integration ./internal/app/... -run TestMCPIntegration
package app_test
import (
"testing"
)
func TestMCPIntegration_Matrix(t *testing.T) {
if testing.Short() {
t.Skip("integration; needs docker")
}
suite := newMCPIntegrationSuite(t)
t.Cleanup(suite.cleanup)
t.Run("StreamableHTTP_FullFlow", suite.testStreamableHTTPFullFlow)
t.Run("LegacySSE_FullFlow", suite.testLegacySSEFullFlow)
t.Run("ScopeViolation_Tool", suite.testScopeViolationTool)
t.Run("ScopeViolation_Project", suite.testScopeViolationProject)
t.Run("VisibilityRespect", suite.testVisibilityRespect)
t.Run("WriteToolAudit", suite.testWriteToolAudit)
t.Run("RateLimit_PerToken", suite.testRateLimitPerToken)
t.Run("ACPSession_TokenLifecycle", suite.testACPSessionTokenLifecycle)
t.Run("StartupReaper", suite.testStartupReaper)
t.Run("PromptsList_FromTemplates", suite.testPromptsListFromTemplates)
t.Run("ResourceRead_NotFound", suite.testResourceReadNotFound)
t.Run("ResourceList_ScopeFilter", suite.testResourceListScopeFilter)
t.Run("BearerVsQueryToken", suite.testBearerVsQueryToken)
t.Run("MCPSDKVersionNegotiation", suite.testMCPSDKVersionNegotiation)
}
type mcpIntegrationSuite struct {
// Will be filled in K2-K5
cleanup func()
}
func newMCPIntegrationSuite(t *testing.T) *mcpIntegrationSuite {
t.Helper()
// Minimal scaffold — actual wiring in K2-K5
return &mcpIntegrationSuite{
cleanup: func() {},
}
}
// All 14 stubs — each skips until its implementation batch fills it in.
func (s *mcpIntegrationSuite) testStreamableHTTPFullFlow(t *testing.T) {
t.Skip("filled in K2")
}
func (s *mcpIntegrationSuite) testLegacySSEFullFlow(t *testing.T) {
t.Skip("filled in K2")
}
func (s *mcpIntegrationSuite) testScopeViolationTool(t *testing.T) {
t.Skip("filled in K3")
}
func (s *mcpIntegrationSuite) testScopeViolationProject(t *testing.T) {
t.Skip("filled in K3")
}
func (s *mcpIntegrationSuite) testVisibilityRespect(t *testing.T) {
t.Skip("filled in K3")
}
func (s *mcpIntegrationSuite) testWriteToolAudit(t *testing.T) {
t.Skip("filled in K3")
}
func (s *mcpIntegrationSuite) testRateLimitPerToken(t *testing.T) {
t.Skip("filled in K4")
}
func (s *mcpIntegrationSuite) testACPSessionTokenLifecycle(t *testing.T) {
t.Skip("filled in K4")
}
func (s *mcpIntegrationSuite) testStartupReaper(t *testing.T) {
t.Skip("filled in K4")
}
func (s *mcpIntegrationSuite) testPromptsListFromTemplates(t *testing.T) {
t.Skip("filled in K5")
}
func (s *mcpIntegrationSuite) testResourceReadNotFound(t *testing.T) {
t.Skip("filled in K5")
}
func (s *mcpIntegrationSuite) testResourceListScopeFilter(t *testing.T) {
t.Skip("filled in K5")
}
func (s *mcpIntegrationSuite) testBearerVsQueryToken(t *testing.T) {
t.Skip("filled in K2")
}
func (s *mcpIntegrationSuite) testMCPSDKVersionNegotiation(t *testing.T) {
t.Skip("filled in K2")
}