Skip to content

Commit

Permalink
spin-ca: Migrate tests from E2E to unit and integration
Browse files Browse the repository at this point in the history
Our tests for the Spin CA don't validate that the resulting TLS bundle
is used by the shim, so migrate the core of the tests to lighterweight
integration and unit tests.

A future E2E that installs a bundle and validates outbound-tls would
also be excellent.
  • Loading branch information
endocrimes committed Aug 14, 2024
1 parent 6d5bd3d commit 02f5c86
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 43 deletions.
43 changes: 0 additions & 43 deletions e2e/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package e2e

import (
"context"
"slices"
"testing"
"time"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/e2e-framework/klient"
Expand Down Expand Up @@ -89,47 +87,6 @@ func TestDefaultSetup(t *testing.T) {
}
return ctx
}).
Assess("ca certificate secret is created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: testCACertSecret,
Namespace: testNamespace,
},
}

if err := wait.For(
conditions.New(client.Resources()).ResourceMatch(secret, func(object k8s.Object) bool {
return true
}),
wait.WithTimeout(time.Minute),
wait.WithInterval(5*time.Second),
); err != nil {
t.Fatal(err)
}
return ctx
}).
Assess("ca certificate secret is mounted to the deployment", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
var deployment appsv1.Deployment
if err := client.Resources().Get(ctx, testSpinAppName, testNamespace, &deployment); err != nil {
t.Fatalf("Failed to get deployment: %s", err)
}

if !slices.ContainsFunc(deployment.Spec.Template.Spec.Volumes, func(v corev1.Volume) bool {
return v.Name == "spin-ca" && v.VolumeSource.Secret.SecretName == testCACertSecret
}) {
t.Fatalf("Failed to add ca bundle volume")
}

if !slices.ContainsFunc(deployment.Spec.Template.Spec.Containers, func(c corev1.Container) bool {
return slices.ContainsFunc(c.VolumeMounts, func(v corev1.VolumeMount) bool {
return v.Name == "spin-ca"
})
}) {
t.Fatalf("Failed to mount ca bundle to container")
}

return ctx
}).
Feature()
testEnv.Test(t, defaultTest)
}
Expand Down
14 changes: 14 additions & 0 deletions internal/controller/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ func TestConstructRuntimeConfigSecretMount_Contract(t *testing.T) {
require.Contains(t, mount.Name, "spin-")
}

func TestConstructCASecretMount(t *testing.T) {
t.Parallel()

volume, mount := constructCASecretMount(context.Background(), "a-secret-name")

// Mount and Volume refer to each other
require.Equal(t, volume.Name, mount.Name)

// uses provided secret name
require.Equal(t, "a-secret-name", volume.Secret.SecretName)

require.True(t, mount.ReadOnly)
}

func TestConstructVolumeMountsForApp_Contract(t *testing.T) {
t.Parallel()

Expand Down
113 changes: 113 additions & 0 deletions internal/controller/spinapp_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"path/filepath"
goruntime "runtime"
"slices"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -431,3 +432,115 @@ func TestConstructDeployment_WithPodLabels(t *testing.T) {
require.Len(t, deployment.Spec.Template.Labels, 3)
require.Equal(t, deployment.Spec.Template.Labels[key], value)
}

func TestReconcile_Integration_Deployment_SpinCAInjection(t *testing.T) {
t.Parallel()

envTest, mgr, _ := setupController(t)

ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFunc()

var wg sync.WaitGroup
wg.Add(1)
go func() {
require.NoError(t, mgr.Start(ctx))
wg.Done()
}()

// Create an executor that creates a deployment with the default Spin CA Secret
executorWithDefaults := &spinv1alpha1.SpinAppExecutor{
ObjectMeta: metav1.ObjectMeta{
Name: "executor-default",
Namespace: "default",
},
Spec: spinv1alpha1.SpinAppExecutorSpec{
CreateDeployment: true,
DeploymentConfig: &spinv1alpha1.ExecutorDeploymentConfig{
RuntimeClassName: "foobar",
InstallDefaultCACerts: true,
},
},
}

// Create an executor that creates a deployment with a custom secret that doesn't
// exist in the cluster
executorWithCustomNonExistentSecret := &spinv1alpha1.SpinAppExecutor{
ObjectMeta: metav1.ObjectMeta{
Name: "executor-custom-name",
Namespace: "default",
},
Spec: spinv1alpha1.SpinAppExecutorSpec{
CreateDeployment: true,
DeploymentConfig: &spinv1alpha1.ExecutorDeploymentConfig{
RuntimeClassName: "foobar",
CACertSecret: "my-custom-secret-name",
InstallDefaultCACerts: true,
},
},
}

require.NoError(t, envTest.k8sClient.Create(ctx, executorWithDefaults))
require.NoError(t, envTest.k8sClient.Create(ctx, executorWithCustomNonExistentSecret))

for _, executor := range []*spinv1alpha1.SpinAppExecutor{
executorWithDefaults,
executorWithCustomNonExistentSecret,
} {
spinApp := &spinv1alpha1.SpinApp{
ObjectMeta: metav1.ObjectMeta{
Name: "app-" + executor.Name,
Namespace: "default",
},
Spec: spinv1alpha1.SpinAppSpec{
Executor: executor.Name,
Image: "ghcr.io/radu-matei/perftest:v1",
},
}
require.NoError(t, envTest.k8sClient.Create(ctx, spinApp))

var deployment appsv1.Deployment
require.Eventually(t, func() bool {
err := envTest.k8sClient.Get(ctx,
types.NamespacedName{
Namespace: "default",
Name: spinApp.Name},
&deployment)
return err == nil
}, 3*time.Second, 100*time.Millisecond)

expectedSecretName := "spin-ca"
if executor.Spec.DeploymentConfig.CACertSecret != "" {
expectedSecretName = executor.Spec.DeploymentConfig.CACertSecret
}

// ensure the secret exists
var secret corev1.Secret
require.Eventually(t, func() bool {
err := envTest.k8sClient.Get(ctx,
types.NamespacedName{
Namespace: "default",
Name: expectedSecretName,
},
&secret)
return err == nil
}, 3*time.Second, 100*time.Millisecond)

if !slices.ContainsFunc(deployment.Spec.Template.Spec.Volumes, func(v corev1.Volume) bool {
return v.Name == "spin-ca" && v.VolumeSource.Secret.SecretName == expectedSecretName
}) {
t.Errorf("deployment does not contain a binding to the correct CA Secret")
}

if !slices.ContainsFunc(deployment.Spec.Template.Spec.Containers, func(c corev1.Container) bool {
return slices.ContainsFunc(c.VolumeMounts, func(v corev1.VolumeMount) bool {
return v.Name == "spin-ca"
})
}) {
t.Fatalf("deployment does not include ca-bundle mount")
}
}
// Terminate the context to force the manager to shut down.
cancelFunc()
wg.Wait()
}

0 comments on commit 02f5c86

Please sign in to comment.