@@ -15,6 +15,7 @@ This MCP server enables AI assistants (like Claude, Gemini, Cursor, and others)
1515 - ` podman/ ` - Podman/Docker CLI abstraction layer with interface definition and CLI implementation.
1616 - ` podman-mcp-server/cmd/ ` - CLI command definition using Cobra framework.
1717 - ` version/ ` - Version information management.
18+ - ` internal/test/ ` – shared test utilities (McpSuite, mock podman helpers).
1819- ` .github/ ` – GitHub-related configuration (Actions workflows, Dependabot).
1920- ` npm/ ` – Node packages that wrap the compiled binaries for distribution through npmjs.com.
2021- ` python/ ` – Python package providing a script that downloads the correct platform binary from the GitHub releases page and runs it for distribution through pypi.org.
@@ -117,80 +118,114 @@ make test
117118
118119### Testing Patterns and Guidelines
119120
120- > ** Note:** Tests are currently written with vanilla ` testing ` package but should be migrated to ` testify/suite `
121- > to match kubernetes-mcp-server patterns. See [ Issue #68 ] ( https://github.com/manusa/podman-mcp-server/issues/68 ) .
121+ Tests use ` testify/suite ` following the kubernetes-mcp-server patterns.
122122
123- #### Target Testing Pattern (testify/suite)
123+ #### Test Suites
124124
125- New tests should use ` testify/suite ` following the kubernetes-mcp-server pattern :
125+ All tests use ` testify/suite ` with the ` test.McpSuite ` base from ` internal/test/ ` :
126126
127127``` go
128+ package mcp_test
129+
130+ import (
131+ " testing"
132+
133+ " github.com/mark3labs/mcp-go/mcp"
134+ " github.com/stretchr/testify/suite"
135+
136+ " github.com/manusa/podman-mcp-server/internal/test"
137+ )
138+
128139type ContainerToolsSuite struct {
129- suite.Suite
130- // test fixtures
140+ test.McpSuite
131141}
132142
133- func ( s * ContainerToolsSuite ) SetupTest ( ) {
134- // setup before each test
143+ func TestContainerTools ( t * testing . T ) {
144+ suite. Run (t, new (ContainerToolsSuite))
135145}
136146
137147func (s *ContainerToolsSuite ) TestContainerList () {
138- s.Run (" returns empty list when no containers" , func () {
139- // test implementation
140- s.Equal (expected, actual)
148+ toolResult , err := s.CallTool (" container_list" , map [string ]interface {}{})
149+ s.Run (" returns OK" , func () {
150+ s.NoError (err)
151+ s.False (toolResult.IsError )
141152 })
142- s.Run (" returns all containers when requested " , func () {
143- // test implementation
153+ s.Run (" lists all containers" , func () {
154+ s. Regexp ( " ^podman container list " , toolResult. Content [ 0 ].(mcp. TextContent ). Text )
144155 })
145156}
146-
147- func TestContainerTools (t *testing .T ) {
148- suite.Run (t, new (ContainerToolsSuite))
149- }
150157```
151158
152159Key patterns:
153- - Use ` testify/suite ` for organizing tests into suites
160+ - Embed ` test.McpSuite ` for MCP server/client setup
161+ - Use ` package mcp_test ` (external test package) to avoid import cycles
154162- Use nested subtests with ` s.Run() ` for related scenarios
155- - Use ` s.Equal() ` , ` s.True() ` , ` s.NoError() ` for assertions
156- - One assertion per test case when possible
163+ - Use ` s.NoError() ` , ` s.False() ` , ` s.Regexp() ` , ` s.Contains() ` for assertions
164+ - Use ` s.Require().NoError() ` for setup assertions that should stop the test
165+
166+ #### Test Infrastructure
167+
168+ The ` internal/test/ ` package provides shared test utilities:
157169
158- #### Current Testing Infrastructure
170+ - ** ` mcp.go ` ** - ` McpSuite ` base suite with:
171+ - ` SetupTest() ` / ` TearDownTest() ` - MCP server and client lifecycle
172+ - ` CallTool(name, args) ` - Call an MCP tool
173+ - ` ListTools() ` - List available tools
174+ - ` WithPodmanOutput(lines...) ` - Inject mock podman output
159175
160- This project currently uses a mock Podman binary approach for testing:
176+ - ** ` podman.go ` ** - Mock podman binary helpers:
177+ - ` WithPodmanBinary(t) ` - Build fake podman and prepend to PATH
161178
162- - The ` testdata/podman/main.go ` file contains a fake podman binary that:
163- - Echoes the command line arguments it receives
164- - Optionally reads from an ` output.txt ` file to provide mock responses
165- - Tests build this fake binary and prepend its directory to PATH
166- - This allows testing MCP tools without requiring an actual Podman installation
179+ - ** ` helpers.go ` ** - General utilities:
180+ - ` Must[T](v, err) ` - Panic on error helper
181+ - ` ReadFile(path...) ` - Read file relative to caller
182+
183+ #### Mock Podman Binary
184+
185+ The ` testdata/podman/main.go ` contains a fake podman binary that:
186+ - Echoes the command line arguments it receives
187+ - Optionally reads from an ` output.txt ` file to provide mock responses
188+
189+ This allows testing MCP tools without requiring an actual Podman installation.
167190
168191#### Test Structure
169192
170- Tests are organized in ` pkg/mcp/ ` alongside the source files:
171- - ` common_test.go ` - Shared test infrastructure (mock binary setup, MCP client helpers)
172- - ` mcp_test.go ` - MCP server integration tests
173- - ` podman_container_test.go ` - Container tool tests
174- - ` podman_image_test.go ` - Image tool tests
175- - ` podman_network_test.go ` - Network tool tests
176- - ` podman_volume_test.go ` - Volume tool tests
193+ Tests are organized in ` pkg/mcp/ ` with external test packages:
194+ - ` mcp_test.go ` - MCP server tests and snapshot testing
195+ - ` podman_container_test.go ` - Container tool tests (` ContainerToolsSuite ` )
196+ - ` podman_image_test.go ` - Image tool tests (` ImageToolsSuite ` )
197+ - ` podman_network_test.go ` - Network tool tests (` NetworkToolsSuite ` )
198+ - ` podman_volume_test.go ` - Volume tool tests (` VolumeToolsSuite ` )
177199
178- #### Test Helpers
200+ #### Snapshot Testing
179201
180- The ` mcpContext ` struct in ` common_test.go ` provides:
181- - ` testCase() ` - Sets up test environment with mock binary and MCP client
182- - ` callTool() ` - Calls an MCP tool with arguments
183- - ` withPodmanOutput() ` - Injects mock output for podman commands
202+ Tool definitions are snapshot tested to detect unintended changes:
203+
204+ ``` go
205+ func (s *McpServerSuite ) TestToolDefinitionsSnapshot () {
206+ tools , err := s.ListTools ()
207+ s.Require ().NoError (err)
208+ s.assertJsonSnapshot (" tool_definitions.json" , tools.Tools )
209+ }
210+ ```
211+
212+ Snapshots are stored in ` pkg/mcp/testdata/ ` . To update snapshots:
213+
214+ ``` bash
215+ make test-update-snapshots
216+ # or
217+ UPDATE_SNAPSHOTS=1 go test ./...
218+ ```
184219
185220#### Writing Tests
186221
187222When adding tests:
188- 1 . Use ` testify/ suite` pattern for new test files .
189- 2 . Use the ` testCase ()` helper to set up the test environment .
190- 3 . Use ` withPodmanOutput ()` to inject expected command output.
191- 4 . Call tools using ` callTool ()` and verify the results .
192- 5 . Test both success and error scenarios .
193- 6 . Use nested subtests with ` s.Run() ` for related scenarios.
223+ 1 . Create a suite struct embedding ` test.McpSuite ` .
224+ 2 . Use ` s.CallTool ()` to invoke MCP tools .
225+ 3 . Use ` s.WithPodmanOutput ()` to inject expected command output.
226+ 4 . Use ` s.Run ()` for nested subtests with related scenarios .
227+ 5 . Use ` s.Regexp("^pattern", text) ` for prefix matching, ` s.Regexp("pattern$", text) ` for suffix .
228+ 6 . Test both success and error scenarios.
194229
195230## Dependencies
196231
@@ -199,7 +234,7 @@ When introducing new modules run `make tidy` so that `go.mod` and `go.sum` remai
199234## Coding style
200235
201236- Go modules target Go ** 1.24** (see ` go.mod ` ).
202- - Tests are written with the standard library ` testing ` package .
237+ - Tests use ` testify/suite ` with the ` test.McpSuite ` base (see Testing section above) .
203238- Build and test steps are defined in the Makefile—keep them working.
204239- Use interfaces for abstraction (see ` pkg/podman/interface.go ` ).
205240
0 commit comments