Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 42 additions & 26 deletions test/e2e/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@ import (

mcpv1alpha1 "github.com/kubernetes-sigs/mcp-lifecycle-operator/api/v1alpha1"
f "github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/category"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/scenario"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/speed"
)

// --- Storage Tests ---

func TestStorageConfigMap(t *testing.T) {
feature := features.New("MCPServer with ConfigMap storage").
WithLabel("type", "configuration").
WithLabel("config", "storage-configmap").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Storage).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
ns := ctx.Value(f.NsKey).(string)
r := cfg.Client().Resources()
Expand Down Expand Up @@ -110,8 +114,9 @@ func TestStorageConfigMap(t *testing.T) {

func TestStorageSecret(t *testing.T) {
feature := features.New("MCPServer with Secret storage").
WithLabel("type", "configuration").
WithLabel("config", "storage-secret").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Storage).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
ns := ctx.Value(f.NsKey).(string)
r := cfg.Client().Resources()
Expand Down Expand Up @@ -181,8 +186,9 @@ func TestStorageSecret(t *testing.T) {

func TestStorageEmptyDir(t *testing.T) {
feature := features.New("MCPServer with EmptyDir storage").
WithLabel("type", "configuration").
WithLabel("config", "storage-emptydir").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Storage).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
sizeLimit := resource.MustParse("100Mi")
return f.SetupMCPServer(ctx, t, cfg, "storage-empty", true,
Expand Down Expand Up @@ -242,8 +248,9 @@ func TestStorageEmptyDir(t *testing.T) {

func TestStorageRecursiveReadOnly(t *testing.T) {
feature := features.New("MCPServer with RecursiveReadOnly storage").
WithLabel("type", "configuration").
WithLabel("config", "storage-recursive-readonly").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Storage).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
ns := ctx.Value(f.NsKey).(string)
r := cfg.Client().Resources()
Expand Down Expand Up @@ -308,8 +315,9 @@ func TestStorageRecursiveReadOnly(t *testing.T) {

func TestStorageMultipleMounts(t *testing.T) {
feature := features.New("MCPServer with multiple storage mounts").
WithLabel("type", "configuration").
WithLabel("config", "storage-multi").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Storage).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
ns := ctx.Value(f.NsKey).(string)
r := cfg.Client().Resources()
Expand Down Expand Up @@ -410,8 +418,9 @@ func TestStorageMultipleMounts(t *testing.T) {

func TestCustomPort(t *testing.T) {
feature := features.New("MCPServer with custom non-default port").
WithLabel("type", "configuration").
WithLabel("config", "port-custom").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Port).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
// Use port 9090 at creation time. The test image only listens on 3001,
// so the pod won't pass readiness, but we verify port propagation.
Expand Down Expand Up @@ -480,8 +489,9 @@ func TestCustomPort(t *testing.T) {

func TestSamePortDifferentNamespaces(t *testing.T) {
feature := features.New("MCPServers with same port in different namespaces").
WithLabel("type", "configuration").
WithLabel("config", "port-namespaces").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Slow).
WithLabel(scenario.Label, scenario.Port).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
// Server A in the default test namespace
ctx = f.SetupMCPServer(ctx, t, cfg, "server-a", true)
Expand Down Expand Up @@ -562,8 +572,9 @@ func TestSamePortDifferentNamespaces(t *testing.T) {

func TestDefaultSecurityContext(t *testing.T) {
feature := features.New("MCPServer with default security context").
WithLabel("type", "configuration").
WithLabel("config", "security-default").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Moderate).
WithLabel(scenario.Label, scenario.Security).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "sec-default", true)
}).
Expand Down Expand Up @@ -610,8 +621,9 @@ func TestDefaultSecurityContext(t *testing.T) {

func TestCustomSecurityContext(t *testing.T) {
feature := features.New("MCPServer with custom security context").
WithLabel("type", "configuration").
WithLabel("config", "security-custom").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Security).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "sec-custom", true,
f.WithSecurityContext(&corev1.SecurityContext{
Expand Down Expand Up @@ -666,8 +678,9 @@ func TestCustomSecurityContext(t *testing.T) {

func TestPodSecurityContext(t *testing.T) {
feature := features.New("MCPServer with pod security context").
WithLabel("type", "configuration").
WithLabel("config", "security-pod").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Security).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "sec-pod", true,
f.WithPodSecurityContext(&corev1.PodSecurityContext{
Expand Down Expand Up @@ -708,8 +721,9 @@ func TestPodSecurityContext(t *testing.T) {

func TestCustomLabelsAndAnnotations(t *testing.T) {
feature := features.New("MCPServer with custom labels and annotations").
WithLabel("type", "configuration").
WithLabel("config", "metadata-custom").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Metadata).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "meta-custom", true,
f.WithExtraLabels(map[string]string{"team": "platform", "env": "test"}),
Expand Down Expand Up @@ -782,8 +796,9 @@ func TestCustomLabelsAndAnnotations(t *testing.T) {

func TestReservedLabelFiltering(t *testing.T) {
feature := features.New("MCPServer reserved label filtering").
WithLabel("type", "configuration").
WithLabel("config", "metadata-reserved").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Metadata).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "meta-reserved", true,
f.WithExtraLabels(map[string]string{
Expand Down Expand Up @@ -825,8 +840,9 @@ func TestReservedLabelFiltering(t *testing.T) {

func TestCustomMetadataUpdate(t *testing.T) {
feature := features.New("MCPServer custom metadata update").
WithLabel("type", "configuration").
WithLabel("config", "metadata-update").
WithLabel(category.Label, category.Configuration).
WithLabel(speed.Label, speed.Moderate).
WithLabel(scenario.Label, scenario.Metadata).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "meta-update", true,
f.WithExtraLabels(map[string]string{"team": "alpha"}),
Expand Down
43 changes: 27 additions & 16 deletions test/e2e/failure_scenarios_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ import (

mcpv1alpha1 "github.com/kubernetes-sigs/mcp-lifecycle-operator/api/v1alpha1"
f "github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/category"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/scenario"
"github.com/kubernetes-sigs/mcp-lifecycle-operator/test/e2e/framework/labels/speed"
)

func TestImagePullFailure(t *testing.T) {
feature := features.New("MCPServer image pull failure").
WithLabel("type", "failure").
WithLabel("failure", "image-pull").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Slow).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "img-pull-fail", false,
f.WithImage("invalid.example.com/nonexistent/image:v0.0.1"),
Expand Down Expand Up @@ -92,8 +96,9 @@ func TestImagePullFailure(t *testing.T) {

func TestContainerCrashLoop(t *testing.T) {
feature := features.New("MCPServer container crash loop").
WithLabel("type", "failure").
WithLabel("failure", "crash-loop").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Moderate).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "crash-loop", false,
f.WithImage("docker.io/library/busybox:1.37"),
Expand Down Expand Up @@ -132,8 +137,9 @@ func TestContainerCrashLoop(t *testing.T) {

func TestMCPHandshakeFailure(t *testing.T) {
feature := features.New("MCPServer handshake failure").
WithLabel("type", "failure").
WithLabel("failure", "mcp-handshake").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "handshake-fail", false,
f.WithPath("/not-mcp"),
Expand Down Expand Up @@ -184,8 +190,9 @@ func TestMCPHandshakeFailure(t *testing.T) {

func TestMissingConfigMapReference(t *testing.T) {
feature := features.New("MCPServer missing ConfigMap reference").
WithLabel("type", "failure").
WithLabel("failure", "missing-configmap").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "missing-cm", false,
f.WithEnvFrom(corev1.EnvFromSource{
Expand Down Expand Up @@ -238,8 +245,9 @@ func TestMissingConfigMapReference(t *testing.T) {

func TestMissingSecretReference(t *testing.T) {
feature := features.New("MCPServer missing Secret reference").
WithLabel("type", "failure").
WithLabel("failure", "missing-secret").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "missing-secret", false,
f.WithEnvFrom(corev1.EnvFromSource{
Expand Down Expand Up @@ -292,8 +300,9 @@ func TestMissingSecretReference(t *testing.T) {

func TestMissingStorageConfigMapReference(t *testing.T) {
feature := features.New("MCPServer missing storage ConfigMap reference").
WithLabel("type", "failure").
WithLabel("failure", "missing-storage-configmap").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Fast).
WithLabel(scenario.Label, scenario.Failure).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "missing-storage", false,
f.WithStorage(mcpv1alpha1.StorageMount{
Expand Down Expand Up @@ -339,8 +348,9 @@ func TestMissingStorageConfigMapReference(t *testing.T) {

func TestRecoveryFromMissingConfigMap(t *testing.T) {
feature := features.New("MCPServer recovery from missing ConfigMap").
WithLabel("type", "recovery").
WithLabel("failure", "missing-configmap").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Moderate).
WithLabel(scenario.Label, scenario.Recovery).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "recovery-cm", false,
f.WithEnvFrom(corev1.EnvFromSource{
Expand Down Expand Up @@ -402,8 +412,9 @@ func TestRecoveryFromMissingConfigMap(t *testing.T) {

func TestRecoveryFromImagePullFailure(t *testing.T) {
feature := features.New("MCPServer recovery from image pull failure").
WithLabel("type", "recovery").
WithLabel("failure", "image-pull").
WithLabel(category.Label, category.Resilience).
WithLabel(speed.Label, speed.Slow).
WithLabel(scenario.Label, scenario.Recovery).
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
return f.SetupMCPServer(ctx, t, cfg, "recovery-img", false,
f.WithImage("invalid.example.com/nonexistent/image:v0.0.1"),
Expand Down
27 changes: 27 additions & 0 deletions test/e2e/framework/labels/category/category.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Copyright 2026 The Kubernetes Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package category

const (
Label = "category"

Lifecycle = "lifecycle"
Configuration = "configuration"
Resilience = "resilience"
Networking = "networking"
Observability = "observability"
)
41 changes: 41 additions & 0 deletions test/e2e/framework/labels/scenario/scenario.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2026 The Kubernetes Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package scenario provides the optional third label dimension for e2e tests.
// Scenarios slice larger categories (lifecycle, configuration, resilience) into
// finer groups. Categories with few tests (networking, observability) intentionally
// omit scenario labels.
package scenario

const (
Label = "scenario"

// Lifecycle scenarios.
Deploy = "deploy"
SpecUpdate = "spec-update"
Drift = "drift"
Ownership = "ownership"

// Configuration scenarios.
Storage = "storage"
Port = "port"
Security = "security"
Metadata = "metadata"

// Resilience scenarios.
Failure = "failure"
Recovery = "recovery"
)
25 changes: 25 additions & 0 deletions test/e2e/framework/labels/speed/speed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright 2026 The Kubernetes Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package speed

const (
Label = "speed"

Fast = "fast"
Moderate = "moderate"
Slow = "slow"
)
Loading
Loading