Skip to content

Commit

Permalink
tests: run KonnectEntityReconciler envtest tests in parallel (#569)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmalek authored Sep 11, 2024
1 parent 3bde12f commit 394c2cf
Showing 1 changed file with 44 additions and 33 deletions.
77 changes: 44 additions & 33 deletions test/envtest/reconciler_setupwithmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
Expand All @@ -27,34 +28,31 @@ import (
)

func TestNewKonnectEntityReconciler(t *testing.T) {
testNewKonnectEntityReconciler(t, konnectv1alpha1.KonnectGatewayControlPlane{}, konnectGatewayControlPlaneTestCases)
testNewKonnectEntityReconciler(t, configurationv1alpha1.KongService{}, nil)
testNewKonnectEntityReconciler(t, configurationv1.KongConsumer{}, nil)
testNewKonnectEntityReconciler(t, configurationv1alpha1.KongRoute{}, nil)
testNewKonnectEntityReconciler(t, configurationv1beta1.KongConsumerGroup{}, nil)
testNewKonnectEntityReconciler(t, configurationv1alpha1.KongPluginBinding{}, nil)
// Setup up the envtest environment and share it across the test cases.
cfg := Setup(t, scheme.Get())

testNewKonnectEntityReconciler(t, cfg, konnectv1alpha1.KonnectGatewayControlPlane{}, konnectGatewayControlPlaneTestCases)
testNewKonnectEntityReconciler(t, cfg, configurationv1alpha1.KongService{}, nil)
testNewKonnectEntityReconciler(t, cfg, configurationv1.KongConsumer{}, nil)
testNewKonnectEntityReconciler(t, cfg, configurationv1alpha1.KongRoute{}, nil)
testNewKonnectEntityReconciler(t, cfg, configurationv1beta1.KongConsumerGroup{}, nil)
testNewKonnectEntityReconciler(t, cfg, configurationv1alpha1.KongPluginBinding{}, nil)
}

const (
testNamespaceName = "test"
envTestWaitDuration = time.Second
envTestWaitTick = 20 * time.Millisecond
)

type konnectEntityReconcilerTestCase struct {
name string
objectOps func(ctx context.Context, t *testing.T, cl client.Client)
eventuallyPredicate func(ctx context.Context, t *testing.T, cl client.Client) bool
objectOps func(ctx context.Context, t *testing.T, cl client.Client, ns *corev1.Namespace)
eventuallyPredicate func(ctx context.Context, t *testing.T, cl client.Client, ns *corev1.Namespace) bool
}

var konnectGatewayControlPlaneTestCases = []konnectEntityReconcilerTestCase{
{
name: "should resolve auth",
objectOps: func(ctx context.Context, t *testing.T, cl client.Client) {
objectOps: func(ctx context.Context, t *testing.T, cl client.Client, ns *corev1.Namespace) {
auth := &konnectv1alpha1.KonnectAPIAuthConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "auth",
Namespace: testNamespaceName,
Namespace: ns.Name,
},
Spec: konnectv1alpha1.KonnectAPIAuthConfigurationSpec{
Type: konnectv1alpha1.KonnectAPIAuthTypeToken,
Expand All @@ -65,7 +63,7 @@ var konnectGatewayControlPlaneTestCases = []konnectEntityReconcilerTestCase{
cp := &konnectv1alpha1.KonnectGatewayControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "cp-1",
Namespace: testNamespaceName,
Namespace: ns.Name,
},
Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{
KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{
Expand All @@ -77,10 +75,17 @@ var konnectGatewayControlPlaneTestCases = []konnectEntityReconcilerTestCase{
}
require.NoError(t, cl.Create(ctx, cp))
},
eventuallyPredicate: func(ctx context.Context, t *testing.T, cl client.Client) bool {
eventuallyPredicate: func(ctx context.Context, t *testing.T, cl client.Client, ns *corev1.Namespace) bool {
cp := &konnectv1alpha1.KonnectGatewayControlPlane{}
err := cl.Get(ctx, k8stypes.NamespacedName{Namespace: testNamespaceName, Name: "cp-1"}, cp)
require.NoError(t, err)
require.NoError(t,
cl.Get(ctx,
k8stypes.NamespacedName{
Namespace: ns.Name,
Name: "cp-1",
},
cp,
),
)
// TODO: setup mock Konnect SDK and verify that Konnect CP is "Created".
return lo.ContainsBy(cp.Status.Conditions, func(condition metav1.Condition) bool {
return condition.Type == conditions.KonnectEntityAPIAuthConfigurationResolvedRefConditionType && condition.Status == metav1.ConditionTrue
Expand All @@ -89,27 +94,28 @@ var konnectGatewayControlPlaneTestCases = []konnectEntityReconcilerTestCase{
},
}

// testNewKonnectEntityReconciler is a helper function to test Konnect entity reconcilers.
// It creates a new namespace for each test case and starts a new controller manager.
// The provided rest.Config designates the Kubernetes API server to use for the tests.
func testNewKonnectEntityReconciler[
T constraints.SupportedKonnectEntityType,
TEnt constraints.EntityType[T],
](
t *testing.T,
cfg *rest.Config,
ent T,
testCases []konnectEntityReconcilerTestCase,
) {
t.Helper()

sdkFactory := &ops.MockSDKFactory{}

t.Run(ent.GetTypeName(), func(t *testing.T) {
s := scheme.Get()
cfg := Setup(t, s)
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: s,
Scheme: scheme.Get(),
Metrics: metricsserver.Options{
// We do not need metrics server so we set BindAddress to 0 to disable it.
BindAddress: "0",
Expand All @@ -118,28 +124,33 @@ func testNewKonnectEntityReconciler[
require.NoError(t, err)

cl := mgr.GetClient()
reconciler := konnect.NewKonnectEntityReconciler[T, TEnt](sdkFactory, false, cl)
reconciler := konnect.NewKonnectEntityReconciler[T, TEnt](&ops.MockSDKFactory{}, false, cl)
require.NoError(t, reconciler.SetupWithManager(ctx, mgr))

err = cl.Create(context.Background(), &corev1.Namespace{
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
GenerateName: "test-",
},
})
require.NoError(t, err)
}
require.NoError(t, cl.Create(ctx, ns))

t.Logf("Starting manager for test case %s", t.Name())
go func() {
err := mgr.Start(ctx)
require.NoError(t, err)
}()

const (
wait = time.Second
tick = 20 * time.Millisecond
)

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tc.objectOps(ctx, t, cl)
tc.objectOps(ctx, t, cl, ns)
require.Eventually(t, func() bool {
return tc.eventuallyPredicate(ctx, t, cl)
}, envTestWaitDuration, envTestWaitTick)
return tc.eventuallyPredicate(ctx, t, cl, ns)
}, wait, tick)
})
}
})
Expand Down

0 comments on commit 394c2cf

Please sign in to comment.