e2e

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Jan 22, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

End-to-End Tests

This directory contains end-to-end tests for ToolHive, including both CLI and HTTP API tests.

Overview

These tests validate ToolHive functionality by exercising the full application stack:

  • CLI Tests: Test command-line interface operations (run, list, stop, restart, etc.)
  • API Tests: Test HTTP API endpoints with a real API server instance
  • Integration Tests: Test interactions between different components

Structure

Test Files
  • *_test.go - Individual test files organized by feature
  • e2e_suite_test.go - Ginkgo test suite setup
  • api_helpers.go - Helper functions for starting API server and making HTTP requests
  • helpers.go - General helper functions for e2e tests
  • mcp_client_helpers.go - MCP client helper utilities
  • oidc_mock.go - Mock OIDC server for authentication tests
  • run_tests.sh - Test runner script
Test Categories

Tests are organized using Ginkgo labels for parallelization and filtering:

Core CLI Tests (Label: core)
  • Client management (client_test.go)
  • Group operations (group_*.go)
  • Server restart (restart_test.go)
  • Export functionality (export_test.go)
  • THVIgnore support (thvignore_test.go)
MCP Protocol Tests (Label: mcp)
  • MCP server operations (osv_mcp_server_test.go, fetch_mcp_server_test.go)
  • Protocol builds (protocol_builds_e2e_test.go)
  • Remote MCP servers (remote_mcp_server_test.go)
  • Inspector functionality (inspector_test.go)
Proxy Tests (Label: proxy)
  • Stdio proxy (proxy_stdio_test.go)
  • OAuth authentication (proxy_oauth_test.go)
  • Tunnel functionality (proxy_tunnel_e2e_test.go)
  • Streamable HTTP proxy (stdio_proxy_over_streamable_http_mcp_server_test.go)
Middleware Tests (Label: middleware)
  • Audit middleware (audit_middleware_e2e_test.go)
  • Authorization (osv_authz_test.go)
  • Telemetry (telemetry_middleware_e2e_test.go)
API Tests (Label: api)
  • Health check endpoint (api_healthcheck_test.go)
  • API server lifecycle and HTTP operations
Other Tests
  • Network isolation (Label: network, isolation)
  • Stability tests (Label: stability)
  • Telemetry validation (Label: telemetry, metrics, validation)
  • SSE endpoint rewriting (Label: sse, endpoint-rewrite)

Running Tests

Prerequisites
  • Go installed
  • Ginkgo CLI installed: go install github.com/onsi/ginkgo/v2/ginkgo@latest
  • Docker, Podman, or Colima container runtime
  • ToolHive binary built (for CLI tests): task build
Run All Tests
cd test/e2e
./run_tests.sh
Run Tests by Label
cd test/e2e

# Run only core CLI tests
E2E_LABEL_FILTER=core ./run_tests.sh

# Run only API tests
E2E_LABEL_FILTER=api ./run_tests.sh

# Run only MCP protocol tests
E2E_LABEL_FILTER=mcp ./run_tests.sh

# Run proxy and middleware tests
E2E_LABEL_FILTER='proxy || middleware' ./run_tests.sh
Run with Ginkgo Directly
cd test/e2e

# Run all tests
ginkgo run --vv .

# Run specific label
ginkgo run --label-filter="api" .

# Run specific test file
ginkgo run --focus-file="api_healthcheck_test.go" .
Run from Project Root
# Run all e2e tests
task test-e2e

# Run with custom label filter
E2E_LABEL_FILTER=api task test-e2e

GitHub Actions Integration

The e2e tests run in parallel in GitHub Actions using label filters. The workflow:

  1. Builds the ToolHive binary once and shares it across jobs
  2. Runs tests in parallel using matrix strategy with label filters:
    • core: Core CLI functionality
    • mcp: MCP protocol tests
    • proxy-mw: Proxy, middleware, and stability tests
    • api: HTTP API tests
  3. Uploads test results as artifacts

See .github/workflows/e2e-tests.yml for the full configuration.

Writing Tests

Adding New CLI Tests
  1. Create a new test file (e.g., feature_test.go)
  2. Add appropriate labels for categorization
  3. Use existing helper functions from helpers.go
  4. Follow the pattern of existing tests

Example:

var _ = Describe("Feature Name", Label("core", "e2e"), func() {
    It("should do something", func() {
        // Test implementation
    })
})
Adding New API Tests
  1. Create a new test file (e.g., api_workloads_test.go)
  2. Use the api label along with specific labels
  3. Use e2e.StartServer() helper to start the API server
  4. Make HTTP requests using the server's methods

Example:

var _ = Describe("Workloads API", Label("api", "workloads"), func() {
    var apiServer *e2e.Server

    BeforeEach(func() {
        config := e2e.NewServerConfig()
        apiServer = e2e.StartServer(config)
    })

    It("should list workloads", func() {
        resp, err := apiServer.Get("/api/v1beta/workloads")
        Expect(err).ToNot(HaveOccurred())
        defer resp.Body.Close()
        Expect(resp.StatusCode).To(Equal(http.StatusOK))
    })
})

Troubleshooting

Container Runtime Not Available

Ensure Docker, Podman, or Colima is running:

docker ps
# or
podman ps
# or
colima status
Binary Not Found (CLI Tests)

Build the ToolHive binary:

task build
# Binary will be at ./bin/thv

Set the binary path if needed:

export THV_BINARY=/path/to/thv
Test Timeouts

Increase the timeout:

TEST_TIMEOUT=20m ./run_tests.sh
Port Conflicts (API Tests)

API tests use random available ports by default. If you encounter port binding issues, the system will automatically find an available port.

Test Best Practices

  1. Use descriptive labels - Make it easy to filter and run related tests
  2. Clean up resources - Use DeferCleanup or AfterEach to clean up
  3. Use unique names - Use GenerateUniqueServerName() for server names
  4. Avoid hardcoded ports - Use random ports for API tests
  5. Test isolation - Ensure tests can run independently
  6. Meaningful assertions - Add context messages to assertions
  7. Use Serial when needed - Mark tests as Serial if they can't run in parallel

Documentation

Overview

Package e2e provides end-to-end testing utilities for ToolHive HTTP API.

Package e2e provides end-to-end testing utilities for ToolHive.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckTHVBinaryAvailable

func CheckTHVBinaryAvailable(config *TestConfig) error

CheckTHVBinaryAvailable checks if the thv binary is available

func CreateAndTrackGroup added in v0.2.9

func CreateAndTrackGroup(config *TestConfig, groupName string, createdGroups *[]string)

CreateAndTrackGroup creates a group and tracks it for cleanup

func DebugServerState

func DebugServerState(config *TestConfig, serverName string)

DebugServerState prints debugging information about a server

func GenerateUniqueServerName added in v0.6.17

func GenerateUniqueServerName(prefix string) string

GenerateUniqueServerName creates a unique server name for tests

func GetMCPServerURL

func GetMCPServerURL(config *TestConfig, serverName string) (string, error)

GetMCPServerURL gets the URL for an MCP server

func GetServerLogs

func GetServerLogs(config *TestConfig, serverName string) (string, error)

GetServerLogs gets the logs for a server to help with debugging

func IsServerRunning added in v0.2.9

func IsServerRunning(config *TestConfig, serverName string) bool

IsServerRunning checks if an MCP server is running

func RemoveGroup added in v0.2.9

func RemoveGroup(config *TestConfig, groupName string) error

RemoveGroup removes a group by name

func StartDockerCommand added in v0.0.40

func StartDockerCommand(args ...string) *exec.Cmd

StartDockerCommand starts a docker command with proper environment setup and returns the command

func StartLongRunningTHVCommand added in v0.0.40

func StartLongRunningTHVCommand(config *TestConfig, args ...string) *exec.Cmd

StartLongRunningTHVCommand starts a long-running ToolHive command and returns the process

func StopAndRemoveMCPServer

func StopAndRemoveMCPServer(config *TestConfig, serverName string) error

StopAndRemoveMCPServer stops and removes an MCP server This function is designed for cleanup and tolerates servers that don't exist

func TestMCPServerBasicFunctionality

func TestMCPServerBasicFunctionality(config *TestConfig, serverURL string) error

TestMCPServerBasicFunctionality tests basic MCP server functionality

func WaitForMCPServer

func WaitForMCPServer(config *TestConfig, serverName string, timeout time.Duration) error

WaitForMCPServer waits for an MCP server to be running

func WaitForMCPServerReady

func WaitForMCPServerReady(config *TestConfig, serverURL string, mode string, timeout time.Duration) error

WaitForMCPServerReady waits for an MCP server to be ready and responsive

func WaitForWorkloadUnhealthy added in v0.2.7

func WaitForWorkloadUnhealthy(config *TestConfig, serverName string, timeout time.Duration) error

WaitForWorkloadUnhealthy waits for a workload to be marked as unhealthy

func WithAccessTokenLifespan added in v0.0.48

func WithAccessTokenLifespan(d time.Duration) func(*fosite.Config)

WithAccessTokenLifespan sets the lifespan of access tokens for the OIDC mock server.

Types

type AuthRequest added in v0.0.40

type AuthRequest struct {
	ClientID      string
	RedirectURI   string
	State         string
	CodeChallenge string
	ResponseType  string
	Scope         string
}

AuthRequest contains the parameters from an OAuth authorization request

type MCPClientHelper

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

MCPClientHelper provides high-level MCP client operations for e2e tests

func NewMCPClientForSSE

func NewMCPClientForSSE(config *TestConfig, serverURL string) (*MCPClientHelper, error)

NewMCPClientForSSE creates a new MCP client for SSE transport

func NewMCPClientForStreamableHTTP added in v0.0.48

func NewMCPClientForStreamableHTTP(config *TestConfig, serverURL string) (*MCPClientHelper, error)

NewMCPClientForStreamableHTTP creates a new MCP client for streamable HTTP transport

func (*MCPClientHelper) CallTool

func (h *MCPClientHelper) CallTool(
	ctx context.Context, toolName string, arguments map[string]interface{},
) (*mcp.CallToolResult, error)

CallTool calls a specific tool with the given arguments

func (*MCPClientHelper) Close

func (h *MCPClientHelper) Close() error

Close closes the MCP client connection

func (*MCPClientHelper) ExpectResourceExists

func (h *MCPClientHelper) ExpectResourceExists(ctx context.Context, uri string)

ExpectResourceExists verifies that a resource with the given URI exists

func (*MCPClientHelper) ExpectToolCall

func (h *MCPClientHelper) ExpectToolCall(
	ctx context.Context, toolName string, arguments map[string]interface{},
) *mcp.CallToolResult

ExpectToolCall verifies that a tool can be called successfully

func (*MCPClientHelper) ExpectToolExists

func (h *MCPClientHelper) ExpectToolExists(ctx context.Context, toolName string)

ExpectToolExists verifies that a tool with the given name exists

func (*MCPClientHelper) Initialize

func (h *MCPClientHelper) Initialize(ctx context.Context) error

Initialize initializes the MCP connection

func (*MCPClientHelper) ListResources

func (h *MCPClientHelper) ListResources(ctx context.Context) (*mcp.ListResourcesResult, error)

ListResources lists all available resources from the MCP server

func (*MCPClientHelper) ListTools

func (h *MCPClientHelper) ListTools(ctx context.Context) (*mcp.ListToolsResult, error)

ListTools lists all available tools from the MCP server

func (*MCPClientHelper) Ping

func (h *MCPClientHelper) Ping(ctx context.Context) error

Ping sends a ping to test connectivity

func (*MCPClientHelper) ReadResource

func (h *MCPClientHelper) ReadResource(ctx context.Context, uri string) (*mcp.ReadResourceResult, error)

ReadResource reads a specific resource

type OIDCMockServer added in v0.0.40

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

OIDCMockServer represents a lightweight OIDC server using Ory Fosite

func NewOIDCMockServer added in v0.0.40

func NewOIDCMockServer(port int, clientID, clientSecret string, opts ...func(*fosite.Config)) (*OIDCMockServer, error)

NewOIDCMockServer creates a new OIDC mock server using Ory Fosite

func (*OIDCMockServer) CompleteAuthRequest added in v0.0.40

func (*OIDCMockServer) CompleteAuthRequest(authReq *AuthRequest) error

CompleteAuthRequest automatically completes an OAuth request by making a callback

func (*OIDCMockServer) EnableAutoComplete added in v0.0.40

func (m *OIDCMockServer) EnableAutoComplete()

EnableAutoComplete enables automatic OAuth flow completion for testing

func (*OIDCMockServer) GetBaseURL added in v0.0.40

func (m *OIDCMockServer) GetBaseURL() string

GetBaseURL returns the base URL of the mock server

func (*OIDCMockServer) Start added in v0.0.40

func (m *OIDCMockServer) Start() error

Start starts the OIDC mock server

func (*OIDCMockServer) Stop added in v0.0.40

func (m *OIDCMockServer) Stop() error

Stop stops the OIDC mock server

func (*OIDCMockServer) WaitForAuthRequest added in v0.0.40

func (m *OIDCMockServer) WaitForAuthRequest(timeout time.Duration) (*AuthRequest, error)

WaitForAuthRequest waits for an OAuth authorization request and returns its parameters

type Server added in v0.8.0

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

Server represents a running API server instance for testing. It runs `thv serve` as a subprocess.

func NewServer added in v0.8.0

func NewServer(config *ServerConfig) (*Server, error)

NewServer creates and starts a new API server instance by running `thv serve` as a subprocess.

func StartServer added in v0.8.0

func StartServer(config *ServerConfig) *Server

StartServer is a helper function that creates and starts an API server and registers cleanup in the Ginkgo AfterEach

func (*Server) BaseURL added in v0.8.0

func (s *Server) BaseURL() string

BaseURL returns the base URL of the API server.

func (*Server) Get added in v0.8.0

func (s *Server) Get(path string) (*http.Response, error)

Get performs a GET request to the specified path.

func (*Server) GetWithHeaders added in v0.8.0

func (s *Server) GetWithHeaders(path string, headers map[string]string) (*http.Response, error)

GetWithHeaders performs a GET request with custom headers.

func (*Server) Stop added in v0.8.0

func (s *Server) Stop() error

Stop stops the API server subprocess.

func (*Server) WaitForReady added in v0.8.0

func (s *Server) WaitForReady() error

WaitForReady waits for the API server to be ready to accept requests.

type ServerConfig added in v0.8.0

type ServerConfig struct {
	Address        string
	StartTimeout   time.Duration
	RequestTimeout time.Duration
	DebugMode      bool
}

ServerConfig holds configuration for the API server in tests

func NewServerConfig added in v0.8.0

func NewServerConfig() *ServerConfig

NewServerConfig creates a new API server configuration with defaults

type THVCommand

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

THVCommand represents a ToolHive CLI command execution

func NewTHVCommand

func NewTHVCommand(config *TestConfig, args ...string) *THVCommand

NewTHVCommand creates a new ToolHive command

func (*THVCommand) ExpectFailure

func (c *THVCommand) ExpectFailure() (string, string, error)

ExpectFailure runs the command and expects it to fail

func (*THVCommand) ExpectSuccess

func (c *THVCommand) ExpectSuccess() (string, string)

ExpectSuccess runs the command and expects it to succeed

func (*THVCommand) Interrupt added in v0.6.12

func (c *THVCommand) Interrupt() error

Interrupt interrupts the command and does NOT wait for it to exit.

func (*THVCommand) Run

func (c *THVCommand) Run() (string, string, error)

Run executes the ToolHive command and returns stdout, stderr, and error

func (*THVCommand) RunWithTimeout

func (c *THVCommand) RunWithTimeout(timeout time.Duration) (string, string, error)

RunWithTimeout executes the ToolHive command with a specific timeout

func (*THVCommand) WithDir

func (c *THVCommand) WithDir(dir string) *THVCommand

WithDir sets the working directory for the command

func (*THVCommand) WithEnv

func (c *THVCommand) WithEnv(env ...string) *THVCommand

WithEnv adds environment variables to the command

func (*THVCommand) WithStdin added in v0.2.9

func (c *THVCommand) WithStdin(stdin string) *THVCommand

WithStdin sets the stdin input for the command

type TestConfig

type TestConfig struct {
	THVBinary    string
	TestTimeout  time.Duration
	CleanupAfter bool
}

TestConfig holds configuration for e2e tests

func NewTestConfig

func NewTestConfig() *TestConfig

NewTestConfig creates a new test configuration with defaults

Directories

Path Synopsis
Package images provides centralized container image references for e2e tests.
Package images provides centralized container image references for e2e tests.
thv-operator
virtualmcp
Package virtualmcp provides helper functions for VirtualMCP E2E tests.
Package virtualmcp provides helper functions for VirtualMCP E2E tests.

Jump to

Keyboard shortcuts

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