testutil

package
v1.39.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: MIT Imports: 14 Imported by: 0

README

Test Utilities

This package wires this server's product toolset groups onto the product-neutral mocks in pkg/testutil, so a product's tests get a ready MCP server from a status code and a canned body.

Which package to import

  • internal/testutil (this one) — writing tests for a product in this repo. Everything below is here, plus the product wiring.
  • pkg/testutil — writing tests for a server built on this repo, whose toolset groups this package knows nothing about. Assemble a server from your own group with testutil.MCPServer(t, group) and drive it with the same ExecuteToolRequest.

Usage

For Teamwork Projects Tests
import "github.com/teamwork/mcp/internal/testutil"

func TestSomething(t *testing.T) {
    mcpServer := testutil.ProjectsMCPServerMock(t, http.StatusOK, []byte(`{"id": 123}`))

    // Use testutil.ExecuteToolRequest for simple cases
    testutil.ExecuteToolRequest(t, mcpServer, "twprojects-get_comment", map[string]any{
        "id": float64(123),
    })
}
For Teamwork Desk Tests
import "github.com/teamwork/mcp/internal/testutil"

func TestSomething(t *testing.T) {
    mcpServer, cleanup := testutil.DeskMCPServerMock(t, http.StatusOK, []byte(`{"ticket_priority": {"id": 123}}`))
    defer cleanup()

    // Use testutil.ExecuteToolRequest for simple cases
    testutil.ExecuteToolRequest(t, mcpServer, "twdesk-get_priority", map[string]any{
        "id": 123,
    })
}
For a server built on this repo
import (
    "github.com/teamwork/mcp/pkg/testutil"
    "github.com/teamwork/mcp/pkg/toolsets"
)

func TestSomething(t *testing.T) {
    engine, lastURL := testutil.EngineMockWithRequestURL(http.StatusOK, []byte(`{"items": []}`))
    mcpServer := testutil.MCPServer(t, mypackage.DefaultToolsetGroup(false, engine))

    testutil.ExecuteToolRequest(t, mcpServer, "twpro-list_items", map[string]any{
        "page_size": float64(50),
    })

    // Assert on the query string, not the response: the mock replies with the
    // same canned body either way, so a dropped parameter looks identical to a
    // working one.
    if got := lastURL.Query().Get("pageSize"); got != "50" {
        t.Errorf("pageSize = %q, want %q", got, "50")
    }
}

Components

Per-product server builders (this package):

  • ProjectsMCPServerMock and its WithRequestBody / WithRequestURL / WithRequestURLs / Routed / Recording / Sequenced variants
  • DeskMCPServerMock, DeskMCPServerMockWithRequestURL, DeskMCPServerMockWithRequest (each returns a cleanup function)
  • SpacesMCPServerMock (returns a cleanup function)
  • ChatMCPServerMock

Re-exported from pkg/testutil so a product's tests need only this package:

  • CheckMessage: validates that a tool execution was successful
  • ExecuteToolRequest: executes a tool request and validates the response
  • ToolRequest: type alias for tool request structures
  • ProjectsEngineMock, DeskClientMock, ProjectsMockRoute, ProjectsRecordedRequest

Product-neutral, in pkg/testutil only:

  • MCPServer / MCPServerWithCustomerURL: assemble a server from any group
  • EngineMock and its capturing, routed, recording and sequenced variants
  • HTTPServerMock / RecordingHTTPServerMock: for tools reached through an *http.Client rather than a twapi.Engine

Documentation

Overview

Package testutil wires this server's product toolset groups onto the product-neutral mocks in pkg/testutil, so a product's tests get a ready MCP server from a status code and a canned body.

Everything reusable lives in pkg/testutil. Only the group wiring belongs here — a server built on this repo writes its own equivalent of this file for its own groups, and shares the rest.

Package testutil provides schema validation helpers for testing MCP tools

Index

Constants

This section is empty.

Variables

View Source
var (
	// ProjectsEngineMock creates a mock twapi.Engine with the given HTTP response.
	ProjectsEngineMock = pkgtestutil.EngineMock

	// DeskClientMock creates a mock desk client with a test server.
	DeskClientMock = pkgtestutil.DeskClientMock

	// CheckMessage validates that a message represents a successful tool
	// execution.
	CheckMessage = pkgtestutil.CheckMessage

	// ExecuteToolRequest executes a tool request and validates the response.
	ExecuteToolRequest = pkgtestutil.ExecuteToolRequest

	// ExecuteToolRequestWithCheckMessage executes a tool request and validates the
	// response with a custom check function.
	ExecuteToolRequestWithCheckMessage = pkgtestutil.ExecuteToolRequestWithCheckMessage
)

Re-exported from pkg/testutil so a product's tests need only this package.

Functions

func ChatMCPServerMock added in v1.21.4

func ChatMCPServerMock(t *testing.T, status int, response []byte) *mcp.Server

ChatMCPServerMock creates a mock MCP server for twchat testing. The twchat tools ride the shared twapi.Engine, so it reuses the engine mock to return the canned HTTP response.

func ChatMCPServerRecordingMock added in v1.39.1

func ChatMCPServerRecordingMock(
	t *testing.T,
	routes []ChatMockRoute,
	fallbackStatus int,
	fallbackBody []byte,
) (*mcp.Server, *[]ChatRecordedRequest)

ChatMCPServerRecordingMock is like ChatMCPServerMock but answers per-path routes and records every request in order, with a fallback for anything the routes miss.

The direct-message tools make more than one call — they identify the authenticated user before resolving a conversation — so a single canned body cannot drive them, and only the recorded requests show that a rejected call sent nothing to the pair or message routes.

func DeskMCPServerMock

func DeskMCPServerMock(t *testing.T, status int, response []byte) (*mcp.Server, func())

DeskMCPServerMock creates a mock MCP server for twdesk testing. It injects the test server URL into the request context so handlers use the correct endpoint.

func DeskMCPServerMockWithRequest added in v1.28.0

func DeskMCPServerMockWithRequest(
	t *testing.T,
	status int,
	response []byte,
) (*mcp.Server, func() (string, url.URL), func())

DeskMCPServerMockWithRequest is like DeskMCPServerMockWithRequestURL but also reports the HTTP method of the most recent request.

The method is what separates some tools from each other: the ticket task link and unlink tools address the same path and differ only in POST versus DELETE, so a test that checks the URL alone passes when the two are swapped.

func DeskMCPServerMockWithRequestURL added in v1.27.1

func DeskMCPServerMockWithRequestURL(
	t *testing.T,
	status int,
	response []byte,
) (*mcp.Server, func() url.URL, func())

DeskMCPServerMockWithRequestURL is like DeskMCPServerMock but also captures the URL of the most recent HTTP request a tool sent, so tests can assert on the query string the tool actually builds.

Asserting the response alone cannot catch a filter or pagination parameter that is never sent: the mock replies with the same canned body regardless, so a dropped parameter looks identical to a working one.

The URL is returned through an accessor rather than a pointer because the capture happens on the httptest server's goroutine.

func GetInvalidTestData added in v1.5.8

func GetInvalidTestData() map[string]map[string]map[string]any

GetInvalidTestData returns invalid test data for all tools

func GetValidTestData added in v1.5.8

func GetValidTestData() map[string]map[string]map[string]any

GetValidTestData returns valid test data for all tools. All required fields (including nullable optional ones) must be provided — pass nil to satisfy a required nullable field without setting a value.

func ProjectsMCPServerMock

func ProjectsMCPServerMock(t *testing.T, status int, response []byte) *mcp.Server

ProjectsMCPServerMock creates a mock MCP server for twprojects testing.

func ProjectsMCPServerMockWithRequestBody added in v1.23.0

func ProjectsMCPServerMockWithRequestBody(t *testing.T, status int, response []byte) (*mcp.Server, *[]byte)

ProjectsMCPServerMockWithRequestBody is like ProjectsMCPServerMock but also captures the body of the most recent HTTP request the engine sent, so tests can assert on the serialized request payload. The returned pointer is populated after a tool invokes the engine.

func ProjectsMCPServerMockWithRequestURL added in v1.26.5

func ProjectsMCPServerMockWithRequestURL(t *testing.T, status int, response []byte) (*mcp.Server, *url.URL)

ProjectsMCPServerMockWithRequestURL is like ProjectsMCPServerMock but also captures the URL of the most recent HTTP request the engine sent, so tests can assert on the query string a tool actually builds.

Asserting the response alone cannot catch a filter or pagination parameter that is never sent: the mock replies with the same canned body regardless, so a dropped parameter looks identical to a working one.

func ProjectsMCPServerMockWithRequestURLs added in v1.28.3

func ProjectsMCPServerMockWithRequestURLs(t *testing.T, status int, response []byte) (*mcp.Server, *[]url.URL)

ProjectsMCPServerMockWithRequestURLs is like ProjectsMCPServerMockWithRequestURL but captures every request the engine sends rather than only the last one.

Use it when the tool under test makes more than one call, because the last URL is then the follow-up rather than the one being asserted on: list_custom_item_records resolves the custom item's field schema after listing, so its list query string is already gone by the time the tool returns, and a test reading lastURL reports the ordering missing from a request that never carried it.

func ProjectsMCPServerRecordingMock added in v1.27.4

func ProjectsMCPServerRecordingMock(
	t *testing.T,
	routes []ProjectsMockRoute,
	fallbackStatus int,
	fallbackBody []byte,
) (*mcp.Server, *[]ProjectsRecordedRequest)

ProjectsMCPServerRecordingMock is like ProjectsMCPServerRoutedMock but records every request in order rather than only the last body. Tools that fan one call out into many writes need this: the order of those writes is part of the contract (move_tasks must patch a parent before its children), and a single captured body cannot show it.

func ProjectsMCPServerRoutedMock added in v1.21.0

func ProjectsMCPServerRoutedMock(
	t *testing.T,
	routes []ProjectsMockRoute,
	fallbackStatus int,
	fallbackBody []byte,
) *mcp.Server

ProjectsMCPServerRoutedMock creates a mock MCP server for twprojects testing whose engine returns different responses based on a substring match against the request URL. Use this when a single tool dispatches calls to multiple endpoints that need distinct status codes (e.g. record create, which lists fields with 200 before posting the record with 201). Requests that don't match any route fall back to fallbackStatus/fallbackBody.

func ProjectsMCPServerRoutedMockWithRequestBody added in v1.25.3

func ProjectsMCPServerRoutedMockWithRequestBody(
	t *testing.T,
	routes []ProjectsMockRoute,
	fallbackStatus int,
	fallbackBody []byte,
) (*mcp.Server, *[]byte)

ProjectsMCPServerRoutedMockWithRequestBody is like ProjectsMCPServerRoutedMock but also captures the body of the most recent HTTP request that carried one, so tests can assert on the serialized payload of the final write while still serving distinct responses per endpoint (e.g. a field-type GET at 200 followed by a value POST at 201).

func ProjectsMCPServerSequencedMock added in v1.24.0

func ProjectsMCPServerSequencedMock(t *testing.T, status int, responses ...[]byte) *mcp.Server

ProjectsMCPServerSequencedMock creates a mock MCP server for twprojects testing whose engine returns the given response bodies in order, one per HTTP request the engine makes. Once the sequence is exhausted the final body is repeated. This lets tests drive a tool's internal pagination loop with a distinct body per page, or exercise a never-ending "hasMore" by supplying a single always-more body. All responses share the same status code.

func SpacesMCPServerMock added in v1.15.0

func SpacesMCPServerMock(t *testing.T, status int, response []byte) (*mcp.Server, func())

SpacesMCPServerMock creates a mock MCP server for twspaces testing. It injects the test server URL into the request context so handlers use the correct endpoint.

Types

type ChatMockRoute added in v1.39.1

type ChatMockRoute = pkgtestutil.MockRoute

ChatMockRoute pairs a substring match against the request URL path with the status and body to return when it matches.

type ChatRecordedRequest added in v1.39.1

type ChatRecordedRequest = pkgtestutil.RecordedRequest

ChatRecordedRequest is one HTTP request captured by ChatMCPServerRecordingMock.

type ExecuteToolRequestOption added in v1.6.2

type ExecuteToolRequestOption = pkgtestutil.ExecuteToolRequestOption

ExecuteToolRequestOption is a function that modifies ExecuteToolRequestOptions.

type ExecuteToolRequestOptions added in v1.6.2

type ExecuteToolRequestOptions = pkgtestutil.ExecuteToolRequestOptions

ExecuteToolRequestOptions represents options for ExecuteToolRequest.

type ProjectsMockRoute added in v1.21.0

type ProjectsMockRoute = pkgtestutil.MockRoute

ProjectsMockRoute pairs a substring match against the request URL path with the status and body to return when it matches.

type ProjectsRecordedRequest added in v1.27.4

type ProjectsRecordedRequest = pkgtestutil.RecordedRequest

ProjectsRecordedRequest is one HTTP request captured by ProjectsMCPServerRecordingMock.

type ProjectsSessionMock

type ProjectsSessionMock = pkgtestutil.SessionMock

ProjectsSessionMock implements a mock session for twprojects testing.

type SchemaValidationTestSuite added in v1.5.8

type SchemaValidationTestSuite struct {
	// contains filtered or unexported fields
}

SchemaValidationTestSuite provides a comprehensive test suite for validating MCP tool JSON schemas

func NewSchemaValidationTestSuite added in v1.5.8

func NewSchemaValidationTestSuite() *SchemaValidationTestSuite

NewSchemaValidationTestSuite creates a new test suite with all twdesk tools

func (*SchemaValidationTestSuite) GetTool added in v1.5.8

func (s *SchemaValidationTestSuite) GetTool(toolName string) (toolsets.ToolWrapper, bool)

GetTool returns a tool by name if it exists

func (*SchemaValidationTestSuite) RunAllSchemaValidationTests added in v1.5.8

func (s *SchemaValidationTestSuite) RunAllSchemaValidationTests(t *testing.T)

RunAllSchemaValidationTests runs comprehensive schema validation tests for all tools

func (*SchemaValidationTestSuite) RunToolSchemaValidation added in v1.5.8

func (s *SchemaValidationTestSuite) RunToolSchemaValidation(t *testing.T, toolName string, tool toolsets.ToolWrapper)

RunToolSchemaValidation runs schema validation tests for a single tool (exported version)

type ToolRequest

type ToolRequest = pkgtestutil.ToolRequest

ToolRequest represents a tool request for testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL