test(mcp): pin session concurrency, document error codes, assert id round-trip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,27 @@ package mcp
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// JSON-RPC application-defined error codes (range -32000 to -32099 per spec).
|
||||
// Tool handlers return one of these from tools/call to signal a typed failure.
|
||||
const (
|
||||
// CodePermissionDenied: caller authenticated but lacks permission for this
|
||||
// resource (e.g. owner not in the allowlist).
|
||||
CodePermissionDenied = -32001
|
||||
|
||||
// CodeNotFound: target repo, file, branch, PR, issue, or workflow run does
|
||||
// not exist.
|
||||
CodeNotFound = -32002
|
||||
|
||||
// CodeConflict: write attempted on stale state (branch already exists,
|
||||
// non-fast-forward push, file modified concurrently).
|
||||
CodeConflict = -32003
|
||||
|
||||
// CodeValidation: arguments failed input validation (bad regex, oversized
|
||||
// payload, missing required field).
|
||||
CodeValidation = -32004
|
||||
|
||||
// CodeUpstreamGitea: Gitea API returned an error this server could not map
|
||||
// to one of the codes above. The original status is in error.data.
|
||||
CodeUpstreamGitea = -32005
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ func TestRequestUnmarshal(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(raw, &req))
|
||||
assert.Equal(t, "2.0", req.JSONRPC)
|
||||
assert.Equal(t, "initialize", req.Method)
|
||||
// ID is opaque; encoding/json decodes JSON numbers into float64 by default.
|
||||
// We don't type-assert in the server — we echo it back unchanged.
|
||||
assert.Equal(t, float64(1), req.ID)
|
||||
}
|
||||
|
||||
func TestErrorResponseShape(t *testing.T) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mcp_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"gitea.d-ma.be/mathias/gitea-mcp/internal/mcp"
|
||||
@@ -20,3 +21,26 @@ func TestSessionStoreIssueAndCheck(t *testing.T) {
|
||||
s.Drop(id)
|
||||
assert.False(t, s.Valid(id))
|
||||
}
|
||||
|
||||
func TestSessionStoreConcurrency(t *testing.T) {
|
||||
s := mcp.NewSessionStore()
|
||||
|
||||
const goroutines = 32
|
||||
const perGoroutine = 100
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(goroutines)
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < perGoroutine; j++ {
|
||||
id := s.Issue()
|
||||
if !s.Valid(id) {
|
||||
t.Errorf("issued id %s reported invalid", id)
|
||||
}
|
||||
s.Drop(id)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user