.cursor/skills/project-testing/SKILL.md
Guide for writing and running tests in kubectl-mtv, including Go unit tests, MCP e2e tests (Python/pytest), and linting. Use when adding tests, running the test suite, or debugging test failures.
npx skillsauth add yaacov/kubectl-mtv project-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Command | Purpose |
|---------|---------|
| make test | Unit tests with coverage |
| make lint | go vet + golangci-lint |
| make fmt | Format Go code |
| make test-e2e | CLI e2e smoke tests (requires cluster) |
| make test-e2e-mcp | E2E MCP tests (local binary) |
| make test-e2e-mcp-image | E2E MCP tests (container image) |
Tests live alongside source files: pkg/mcp/tools/mtv_read_test.go next to mtv_read.go.
func TestMyFunction(t *testing.T) {
tests := []struct {
name string
input string
expected string
wantErr bool
}{
{name: "valid input", input: "foo", expected: "bar"},
{name: "empty input", input: "", wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := MyFunction(tt.input)
if tt.wantErr {
if err == nil {
t.Errorf("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != tt.expected {
t.Errorf("got %q, want %q", result, tt.expected)
}
})
}
}
Common helpers used in the codebase:
testRegistry() -- creates a registry from test data for MCP tool testsbuildTestBinary() -- builds the kubectl-mtv binary for integration-style teststestdataPath() -- resolves paths to testdata/ fixturesfindRepoRoot() -- locates the repo root from any test directoryloadRealRegistry() -- loads testdata/help_machine_output.json for registry testsUse t.Helper() in shared helper functions and t.Skipf() when fixtures or binaries are unavailable.
Fixtures live in testdata/ directories next to test files:
pkg/mcp/discovery/testdata/help_machine_output.json -- snapshot of help --machine outputmake test # All unit tests with coverage
go test ./pkg/mcp/tools/... # Specific package
go test -run TestMyFunc ./pkg/... # Specific test
Coverage output: coverage.out (generated by make test).
Located in tests/e2e_smoke.py. Tests the CLI binary end-to-end against a live OpenShift cluster with MTV/Forklift installed.
--client, full version, JSON output--skip-logs, JSON/markdown output--all, get, specific setting, JSON/YAML outputget provider <name>, describe provider <name>, get plan <name>, describe plan <name>--machine schema (JSON/YAML, --read-only, --write, --short)make test-e2e # Build + run smoke tests
make build && python3 tests/e2e_smoke.py # Manual
Uses stdlib only (no pytest). A main() calls test_* functions, each invoking the binary via subprocess.run with 60s timeout. Helpers assert_exit_ok, assert_exit_fail, assert_contains, assert_valid_json track pass/fail counts. Exits 0 on all pass, 1 on any failure.
Dynamic tests (describe, get by name) discover resources at runtime and skip gracefully if none exist.
Located in e2e/mcp/. These test the MCP server end-to-end via SSE.
e2e/mcp/
├── conftest.py # Shared fixtures and helpers
├── pyproject.toml # pytest config, dependencies
├── Makefile # Server lifecycle + test targets
├── setup/ # Setup verification tests
├── providers/ # Provider CRUD tests
├── hosts/ # Host CRUD tests
├── plans/ # Plan CRUD tests
├── mappings/ # Mapping read tests
├── inventory/ # Inventory read tests
├── health/ # Health check tests
└── auth/ # Auth tests
conftest.py)mcp_session (session) -- SSE ClientSession with K8s authmcp_server_process (session) -- verifies server reachabilitycleanup_test_resources (session, autouse) -- deletes test resources after suitecall_toolresult = await call_tool(mcp_session, "mtv_read", {
"command": "get plan",
"flags": {"namespace": "my-ns", "output": "json"}
})
Required: GOVC_URL, GOVC_USERNAME, GOVC_PASSWORD, KUBE_API_URL, KUBE_TOKEN, ESXI_HOST_NAME, COLD_VMS, WARM_VMS, NETWORK_PAIRS, STORAGE_PAIRS.
Optional: MCP_SSE_URL (default http://127.0.0.1:18443/sse).
make test-e2e-mcp # Build binary + start server + run tests + stop
make test-e2e-mcp-image MCP_IMAGE=quay.io/yaacov/kubectl-mtv-mcp-server:latest
Or manually:
cd e2e/mcp
make server-start # Start MCP server in background
make test # Run pytest
make server-stop # Stop server
Tests use @pytest.mark.order(N) for execution order. The testpaths in pyproject.toml controls directory order: setup -> providers -> hosts -> plans -> mappings -> inventory -> health.
make lint # go vet + golangci-lint
make fmt # go fmt ./...
Fix lint issues before committing. The CI does not run linting automatically on PR, but it is expected to pass locally.
development
Step-by-step guide for updating the kubev2v/forklift Go dependency in kubectl-mtv. Use when bumping the forklift version, syncing settings or CRD types, or checking for upstream changes.
tools
Reference for building, releasing, publishing images, and deploying kubectl-mtv. Use when creating releases, building binaries or container images, deploying to OpenShift, or updating the Krew plugin index.
tools
Guide for adding or modifying MCP tools and understanding command discovery in kubectl-mtv. Use when working on the MCP server, adding new tools, or changing how commands are exposed to AI assistants.
documentation
Guide for adding and editing chapters in the kubectl-mtv technical guide (Jekyll + GitHub Pages). Use when writing documentation, adding chapters, or updating the guide table of contents.