Description
Create a Ginkgo/Gomega E2E test suite in test/e2e/thv-operator/authserver/ that exercises the new authServerRef field on both MCPServer and MCPRemoteProxy resources against a real Kubernetes cluster. These tests validate that the operator correctly resolves authServerRef, generates the expected RunConfig ConfigMap entries, detects conflicts and type mismatches, and preserves backward compatibility with the existing externalAuthConfigRef path. This is Phase 2 of RFC-0050 and builds on the CRD and controller changes delivered in #4640.
Context
#4640 adds the authServerRef field, conflict validation, type validation, and watch handler updates. Without E2E tests, there is no verification that these changes work correctly in a real Kubernetes environment end-to-end -- from resource creation through reconciliation to ConfigMap generation. The E2E suite covers the full operator reconciliation path, including status phase transitions and error condition reporting, which cannot be verified by unit tests alone.
Dependencies: #4640 (CRD types, controller logic, and unit tests)
Blocks: None
Acceptance Criteria
Technical Approach
Recommended Implementation
Create a new Ginkgo test suite under test/e2e/thv-operator/authserver/ following the established pattern from test/e2e/thv-operator/virtualmcp/. The suite connects to a real Kubernetes cluster via kubeconfig, creates test resources in the default namespace, and uses Eventually polling to wait for status transitions.
Each test case creates the necessary MCPExternalAuthConfig resources (embedded auth server, AWS STS, unauthenticated), then creates the MCPServer or MCPRemoteProxy referencing them via authServerRef and/or externalAuthConfigRef. Assertions verify:
- Happy path tests: Poll for
Running/Ready phase, then fetch the <name>-runconfig ConfigMap and unmarshal the runconfig.json data to verify the expected auth config fields are present.
- Error tests (conflict, type mismatch): Poll for
Failed phase and check that status conditions contain the expected error message substring.
- Backward compatibility tests: Create resources using only
externalAuthConfigRef with type: embeddedAuthServer and verify they still reach Running/Ready phase.
The MCPRemoteProxy combined test (authServerRef + externalAuthConfigRef with awsSts) is the primary use case motivating RFC-0050 and deserves particular attention -- verify both embedded_auth_server_config and aws_sts_config keys exist in the RunConfig JSON.
Use AfterAll cleanup blocks to delete all test resources. Use Ordered containers so resources are created once and assertions run in sequence.
Patterns & Frameworks
- Ginkgo/Gomega BDD-style: Follow the
Describe/Context/It structure used in test/e2e/thv-operator/virtualmcp/
- Suite bootstrap: Mirror
virtualmcp/suite_test.go for kubeconfig loading, scheme registration, and client creation
- Eventually polling: Use
gomega.Eventually with 2-3 minute timeouts and 1-second polling for status checks
- JustAfterEach state dump: Include the same failure diagnostic dump pattern from
virtualmcp/suite_test.go for debugging test failures
- Resource cleanup: Use
AfterAll with client.Delete to clean up test resources; ignore NotFound errors
Code Pointers
test/e2e/thv-operator/virtualmcp/suite_test.go - Suite bootstrap pattern to replicate: kubeconfig loading, scheme registration, k8s client setup, JustAfterEach state dump
test/e2e/thv-operator/virtualmcp/helpers.go - Helper function patterns (wait for ready, check pods, etc.) to adapt for MCPServer/MCPRemoteProxy status checks
test/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go - Pattern for creating MCPExternalAuthConfig resources and MCPServer resources that reference them
test/e2e/thv-operator/virtualmcp/virtualmcp_authserver_config_test.go - Pattern for testing auth server configuration validation via status conditions
cmd/thv-operator/api/v1alpha1/mcpserver_types.go - MCPServer phase constants (MCPServerPhaseRunning, MCPServerPhaseFailed) and condition types
cmd/thv-operator/api/v1alpha1/mcpremoteproxy_types.go - MCPRemoteProxy phase constants (MCPRemoteProxyPhaseReady, MCPRemoteProxyPhaseFailed) and condition types
cmd/thv-operator/controllers/mcpserver_runconfig.go (line 52) - ConfigMap naming convention: fmt.Sprintf("%s-runconfig", m.Name)
pkg/runner/config.go - RunConfig struct with EmbeddedAuthServerConfig and AWSStsConfig fields for JSON unmarshaling assertions
Component Interfaces
Test helper signatures to implement in helpers.go:
// WaitForMCPServerPhase polls until an MCPServer reaches the expected phase
func WaitForMCPServerPhase(
ctx context.Context,
c client.Client,
name, namespace string,
expectedPhase mcpv1alpha1.MCPServerPhase,
timeout, pollingInterval time.Duration,
)
// WaitForMCPRemoteProxyPhase polls until an MCPRemoteProxy reaches the expected phase
func WaitForMCPRemoteProxyPhase(
ctx context.Context,
c client.Client,
name, namespace string,
expectedPhase mcpv1alpha1.MCPRemoteProxyPhase,
timeout, pollingInterval time.Duration,
)
// GetRunConfigFromConfigMap fetches the runconfig ConfigMap and returns the parsed JSON
func GetRunConfigFromConfigMap(
ctx context.Context,
c client.Client,
resourceName, namespace string,
) (map[string]interface{}, error)
// ExpectMCPServerConditionMessage waits for a condition with a message containing the substring
func ExpectMCPServerConditionMessage(
ctx context.Context,
c client.Client,
name, namespace string,
conditionType string,
messageSubstring string,
timeout, pollingInterval time.Duration,
)
MCPExternalAuthConfig test fixtures:
// Embedded auth server config for authServerRef tests
embeddedAuthConfig := &mcpv1alpha1.MCPExternalAuthConfig{
ObjectMeta: metav1.ObjectMeta{Name: "test-embedded-auth", Namespace: namespace},
Spec: mcpv1alpha1.MCPExternalAuthConfigSpec{
Type: mcpv1alpha1.ExternalAuthTypeEmbeddedAuthServer,
EmbeddedAuthServer: &mcpv1alpha1.EmbeddedAuthServerConfig{
Issuer: "http://localhost:9090",
UpstreamProviders: []mcpv1alpha1.UpstreamProviderConfig{
{Name: "test", Type: mcpv1alpha1.UpstreamProviderTypeOIDC,
OIDCConfig: &mcpv1alpha1.OIDCUpstreamConfig{
IssuerURL: "https://accounts.google.com",
ClientID: "test-client-id",
}},
},
},
},
}
// AWS STS config for combined auth test
awsStsConfig := &mcpv1alpha1.MCPExternalAuthConfig{
ObjectMeta: metav1.ObjectMeta{Name: "test-aws-sts", Namespace: namespace},
Spec: mcpv1alpha1.MCPExternalAuthConfigSpec{
Type: mcpv1alpha1.ExternalAuthTypeAWSSts,
AWSSts: &mcpv1alpha1.AWSStsConfig{
Region: "us-east-1",
FallbackRoleArn: "arn:aws:iam::123456789012:role/test-role",
},
},
}
MCPServer with authServerRef:
server := &mcpv1alpha1.MCPServer{
ObjectMeta: metav1.ObjectMeta{Name: "test-authserverref", Namespace: namespace},
Spec: mcpv1alpha1.MCPServerSpec{
Image: images.GofetchServerImage,
Transport: "streamable-http",
AuthServerRef: &corev1.TypedLocalObjectReference{
Kind: "MCPExternalAuthConfig",
Name: "test-embedded-auth",
},
},
}
Testing Strategy
MCPServer Tests
MCPRemoteProxy Tests
Edge Cases
Out of Scope
References
Description
Create a Ginkgo/Gomega E2E test suite in
test/e2e/thv-operator/authserver/that exercises the newauthServerReffield on bothMCPServerandMCPRemoteProxyresources against a real Kubernetes cluster. These tests validate that the operator correctly resolvesauthServerRef, generates the expected RunConfig ConfigMap entries, detects conflicts and type mismatches, and preserves backward compatibility with the existingexternalAuthConfigRefpath. This is Phase 2 of RFC-0050 and builds on the CRD and controller changes delivered in #4640.Context
#4640 adds the
authServerReffield, conflict validation, type validation, and watch handler updates. Without E2E tests, there is no verification that these changes work correctly in a real Kubernetes environment end-to-end -- from resource creation through reconciliation to ConfigMap generation. The E2E suite covers the full operator reconciliation path, including status phase transitions and error condition reporting, which cannot be verified by unit tests alone.Dependencies: #4640 (CRD types, controller logic, and unit tests)
Blocks: None
Acceptance Criteria
test/e2e/thv-operator/authserver/exists withsuite_test.go,helpers.go, and test filesauthServerRefpointing totype: embeddedAuthServerreachesRunningphase and the<name>-runconfigConfigMap containsembedded_auth_server_configauthServerRefandexternalAuthConfigRefpointing totype: embeddedAuthServerconfigs entersFailedphase with an error condition indicating conflictauthServerRefpointing to a non-embeddedAuthServertype (e.g.,unauthenticated) entersFailedphase with an error condition indicating type mismatchexternalAuthConfigRefpointing totype: embeddedAuthServer(noauthServerRef) still reachesRunningphase (backward compatibility)authServerRefpointing totype: embeddedAuthServerreachesReadyphase and the ConfigMap containsembedded_auth_server_configauthServerRef(embeddedAuthServer) +externalAuthConfigRef(awsSts) reachesReadyphase and the ConfigMap contains bothembedded_auth_server_configandaws_sts_configauthServerRefandexternalAuthConfigRefpointing totype: embeddedAuthServerentersFailedphase with an error condition indicating conflictauthServerRefpointing to a non-embeddedAuthServertype entersFailedphase with an error condition indicating type mismatchexternalAuthConfigRefpointing totype: embeddedAuthServer(noauthServerRef) still reachesReadyphase (backward compatibility)Technical Approach
Recommended Implementation
Create a new Ginkgo test suite under
test/e2e/thv-operator/authserver/following the established pattern fromtest/e2e/thv-operator/virtualmcp/. The suite connects to a real Kubernetes cluster via kubeconfig, creates test resources in thedefaultnamespace, and usesEventuallypolling to wait for status transitions.Each test case creates the necessary
MCPExternalAuthConfigresources (embedded auth server, AWS STS, unauthenticated), then creates theMCPServerorMCPRemoteProxyreferencing them viaauthServerRefand/orexternalAuthConfigRef. Assertions verify:Running/Readyphase, then fetch the<name>-runconfigConfigMap and unmarshal therunconfig.jsondata to verify the expected auth config fields are present.Failedphase and check that status conditions contain the expected error message substring.externalAuthConfigRefwithtype: embeddedAuthServerand verify they still reachRunning/Readyphase.The MCPRemoteProxy combined test (authServerRef + externalAuthConfigRef with awsSts) is the primary use case motivating RFC-0050 and deserves particular attention -- verify both
embedded_auth_server_configandaws_sts_configkeys exist in the RunConfig JSON.Use
AfterAllcleanup blocks to delete all test resources. UseOrderedcontainers so resources are created once and assertions run in sequence.Patterns & Frameworks
Describe/Context/Itstructure used intest/e2e/thv-operator/virtualmcp/virtualmcp/suite_test.gofor kubeconfig loading, scheme registration, and client creationgomega.Eventuallywith 2-3 minute timeouts and 1-second polling for status checksvirtualmcp/suite_test.gofor debugging test failuresAfterAllwithclient.Deleteto clean up test resources; ignore NotFound errorsCode Pointers
test/e2e/thv-operator/virtualmcp/suite_test.go- Suite bootstrap pattern to replicate: kubeconfig loading, scheme registration, k8s client setup, JustAfterEach state dumptest/e2e/thv-operator/virtualmcp/helpers.go- Helper function patterns (wait for ready, check pods, etc.) to adapt for MCPServer/MCPRemoteProxy status checkstest/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go- Pattern for creatingMCPExternalAuthConfigresources andMCPServerresources that reference themtest/e2e/thv-operator/virtualmcp/virtualmcp_authserver_config_test.go- Pattern for testing auth server configuration validation via status conditionscmd/thv-operator/api/v1alpha1/mcpserver_types.go- MCPServer phase constants (MCPServerPhaseRunning,MCPServerPhaseFailed) and condition typescmd/thv-operator/api/v1alpha1/mcpremoteproxy_types.go- MCPRemoteProxy phase constants (MCPRemoteProxyPhaseReady,MCPRemoteProxyPhaseFailed) and condition typescmd/thv-operator/controllers/mcpserver_runconfig.go(line 52) - ConfigMap naming convention:fmt.Sprintf("%s-runconfig", m.Name)pkg/runner/config.go- RunConfig struct withEmbeddedAuthServerConfigandAWSStsConfigfields for JSON unmarshaling assertionsComponent Interfaces
Test helper signatures to implement in
helpers.go:MCPExternalAuthConfig test fixtures:
MCPServer with authServerRef:
Testing Strategy
MCPServer Tests
authServerRef-> Running phase, ConfigMaprunconfig.jsoncontainsembedded_auth_server_configkeyauthServerRef+externalAuthConfigRefboth referencingtype: embeddedAuthServer-> Failed phase, error message mentions "cannot both configure"authServerRefpointing totype: unauthenticated-> Failed phase, error message mentions expected typeexternalAuthConfigRefpointing totype: embeddedAuthServer(noauthServerRef) -> Running phaseMCPRemoteProxy Tests
authServerRef-> Ready phase, ConfigMap containsembedded_auth_server_configauthServerRef(embeddedAuthServer) +externalAuthConfigRef(awsSts) -> Ready phase, ConfigMap contains bothembedded_auth_server_configandaws_sts_configtype: embeddedAuthServer-> Failed phaseauthServerRefpointing to non-embeddedAuthServer type -> Failed phaseexternalAuthConfigReftotype: embeddedAuthServer(noauthServerRef) -> Ready phaseEdge Cases
authServerRefwithapiGroupomitted (nil) works correctly (the controller should accept this)Out of Scope
virtualmcppattern)thv run)References