From e98aba136ac54bd83740632505a1ee75707e2d4d Mon Sep 17 00:00:00 2001 From: 4t8dd Date: Sun, 30 Nov 2025 12:17:04 +0800 Subject: [PATCH] Centralize container image references in e2e tests Create a dedicated package for container image constants used across e2e tests to provide a single source of truth for image versions. Each image is now defined with three constants: - imageURL: base image path (unexported) - imageTag: version tag (unexported) - Image: combined reference (exported) This structure makes version updates simpler by allowing changes to only the tag constant while keeping the base URL unchanged. Updated test files: - test/e2e/telemetry_metrics_validation_e2e_test.go - test/e2e/thv-operator/virtualmcp/helpers.go - test/e2e/thv-operator/virtualmcp/virtualmcp_discovered_mode_test.go - test/e2e/thv-operator/virtualmcp/virtualmcp_inline_auth_test.go - test/e2e/thv-operator/virtualmcp/virtualmcp_tokenexchange_test.go Fixes #2786 Signed-off-by: 4t8dd --- test/e2e/images/images.go | 42 +++++++++++++++++++ .../telemetry_metrics_validation_e2e_test.go | 3 +- test/e2e/thv-operator/virtualmcp/helpers.go | 7 ++-- .../virtualmcp_auth_discovery_test.go | 7 ++-- .../virtualmcp_discovered_mode_test.go | 5 ++- .../virtualmcp/virtualmcp_inline_auth_test.go | 5 ++- .../virtualmcp_tokenexchange_test.go | 3 +- .../virtualmcp_yardstick_base_test.go | 3 +- 8 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 test/e2e/images/images.go diff --git a/test/e2e/images/images.go b/test/e2e/images/images.go new file mode 100644 index 000000000..8ac947ae3 --- /dev/null +++ b/test/e2e/images/images.go @@ -0,0 +1,42 @@ +// Package images provides centralized container image references for e2e tests. +// This package serves as a single source of truth for all container images used +// in end-to-end testing, making it easier to maintain versions and enabling +// automated dependency updates through tools like Renovate. +// +// Each image is composed of an imageURL (base path) and imageTag (version). +// The complete Image constant combines the URL and tag for use in tests. +package images + +const ( + yardstickServerImageURL = "ghcr.io/stackloklabs/yardstick/yardstick-server" + yardstickServerImageTag = "0.0.2" + // YardstickServerImage is used in operator tests across multiple transport protocols + // (stdio, SSE, streamable-http) and tenancy modes. + // Note: This image is also referenced in 8 YAML fixture files under + // test/e2e/chainsaw/operator/. Those files are declarative Kubernetes manifests + // and cannot import Go constants directly. + YardstickServerImage = yardstickServerImageURL + ":" + yardstickServerImageTag + + gofetchServerImageURL = "ghcr.io/stackloklabs/gofetch/server" + gofetchServerImageTag = "1.0.1" + // GofetchServerImage is used for testing virtual MCP server features, including + // authentication flows and backend aggregation. + GofetchServerImage = gofetchServerImageURL + ":" + gofetchServerImageTag + + osvmcpServerImageURL = "ghcr.io/stackloklabs/osv-mcp/server" + osvmcpServerImageTag = "0.0.7" + // OSVMCPServerImage is used for testing discovered mode aggregation and telemetry + // metrics validation. + OSVMCPServerImage = osvmcpServerImageURL + ":" + osvmcpServerImageTag + + pythonImageURL = "python" + pythonImageTag = "3.9-slim" + // PythonImage is used for deploying mock OIDC servers and instrumented backend servers + // in Kubernetes tests. These run Flask-based Python services for testing authentication flows. + PythonImage = pythonImageURL + ":" + pythonImageTag + + curlImageURL = "curlimages/curl" + curlImageTag = "latest" + // CurlImage is used to query service endpoints and gather statistics during Kubernetes tests. + CurlImage = curlImageURL + ":" + curlImageTag +) diff --git a/test/e2e/telemetry_metrics_validation_e2e_test.go b/test/e2e/telemetry_metrics_validation_e2e_test.go index 0afdc31da..83f14a426 100644 --- a/test/e2e/telemetry_metrics_validation_e2e_test.go +++ b/test/e2e/telemetry_metrics_validation_e2e_test.go @@ -16,6 +16,7 @@ import ( "github.com/stacklok/toolhive/pkg/transport/types" "github.com/stacklok/toolhive/test/e2e" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("Telemetry Metrics Validation E2E", Label("telemetry", "metrics", "validation", "e2e"), Serial, func() { @@ -88,7 +89,7 @@ var _ = Describe("Telemetry Metrics Validation E2E", Label("telemetry", "metrics "--transport", types.TransportTypeSSE.String(), "--otel-enable-prometheus-metrics-path", "--name", inferredName, // Still need explicit name for cleanup - "ghcr.io/stackloklabs/osv-mcp/server:0.0.7", + images.OSVMCPServerImage, ).ExpectSuccess() // Update workloadName for cleanup diff --git a/test/e2e/thv-operator/virtualmcp/helpers.go b/test/e2e/thv-operator/virtualmcp/helpers.go index 9f7940a5c..2be20fe20 100644 --- a/test/e2e/thv-operator/virtualmcp/helpers.go +++ b/test/e2e/thv-operator/virtualmcp/helpers.go @@ -21,6 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) // WaitForVirtualMCPServerReady waits for a VirtualMCPServer to reach Ready status @@ -294,7 +295,7 @@ func DeployMockOIDCServerHTTP(ctx context.Context, c client.Client, namespace, s Containers: []corev1.Container{ { Name: "mock-oidc", - Image: "python:3.9-slim", + Image: images.PythonImage, Command: []string{"sh", "-c"}, Args: []string{MockOIDCServerHTTPScript}, Ports: []corev1.ContainerPort{ @@ -353,7 +354,7 @@ func DeployInstrumentedBackendServer(ctx context.Context, c client.Client, names Containers: []corev1.Container{ { Name: "instrumented-backend", - Image: "python:3.9-slim", + Image: images.PythonImage, Command: []string{"sh", "-c"}, Args: []string{InstrumentedBackendScript}, Ports: []corev1.ContainerPort{ @@ -452,7 +453,7 @@ func GetServiceStats(ctx context.Context, c client.Client, namespace, serviceNam Containers: []corev1.Container{ { Name: "curl", - Image: "curlimages/curl:latest", + Image: images.CurlImage, Command: []string{"curl", "-s", fmt.Sprintf("http://%s.%s.svc.cluster.local:%d/stats", serviceName, namespace, port)}, }, }, diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_auth_discovery_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_auth_discovery_test.go index 27060fbca..93d4f53a6 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_auth_discovery_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_auth_discovery_test.go @@ -17,6 +17,7 @@ import ( "k8s.io/apimachinery/pkg/types" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("VirtualMCPServer Auth Discovery", Ordered, func() { @@ -142,7 +143,7 @@ var _ = Describe("VirtualMCPServer Auth Discovery", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, @@ -161,7 +162,7 @@ var _ = Describe("VirtualMCPServer Auth Discovery", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/osv-mcp/server:0.0.7", + Image: images.OSVMCPServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, @@ -180,7 +181,7 @@ var _ = Describe("VirtualMCPServer Auth Discovery", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_discovered_mode_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_discovered_mode_test.go index 5e07c31eb..7e3f7de7d 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_discovered_mode_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_discovered_mode_test.go @@ -16,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/types" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("VirtualMCPServer Discovered Mode", Ordered, func() { @@ -67,7 +68,7 @@ var _ = Describe("VirtualMCPServer Discovered Mode", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, @@ -83,7 +84,7 @@ var _ = Describe("VirtualMCPServer Discovered Mode", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/osv-mcp/server:0.0.7", + Image: images.OSVMCPServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_inline_auth_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_inline_auth_test.go index 2cbbc0054..3e68ab784 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_inline_auth_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_inline_auth_test.go @@ -15,6 +15,7 @@ import ( "k8s.io/apimachinery/pkg/types" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("VirtualMCPServer Inline Auth with Anonymous Incoming", Ordered, func() { @@ -65,7 +66,7 @@ var _ = Describe("VirtualMCPServer Inline Auth with Anonymous Incoming", Ordered }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, @@ -285,7 +286,7 @@ var _ = Describe("VirtualMCPServer Inline Auth with OIDC Incoming", Ordered, fun }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_tokenexchange_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_tokenexchange_test.go index 74ac5d8f6..71dc205d4 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_tokenexchange_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_tokenexchange_test.go @@ -14,6 +14,7 @@ import ( "k8s.io/apimachinery/pkg/types" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("VirtualMCPServer Token Exchange Auth", Ordered, func() { @@ -110,7 +111,7 @@ var _ = Describe("VirtualMCPServer Token Exchange Auth", Ordered, func() { }, Spec: mcpv1alpha1.MCPServerSpec{ GroupRef: mcpGroupName, - Image: "ghcr.io/stackloklabs/gofetch/server:1.0.1", + Image: images.GofetchServerImage, Transport: "streamable-http", ProxyPort: 8080, McpPort: 8080, diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_yardstick_base_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_yardstick_base_test.go index f7f3d5351..f6ac7ce8a 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_yardstick_base_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_yardstick_base_test.go @@ -14,13 +14,14 @@ import ( "k8s.io/apimachinery/pkg/types" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" + "github.com/stacklok/toolhive/test/e2e/images" ) // Compile-time check to ensure corev1 is used (for Service type) var _ = corev1.ServiceSpec{} // YardstickImage is the container image for the yardstick MCP server -const YardstickImage = "ghcr.io/stackloklabs/yardstick/yardstick-server:0.0.2" +const YardstickImage = images.YardstickServerImage var _ = Describe("VirtualMCPServer Yardstick Base", Ordered, func() { var (