Skip to content

Commit

Permalink
test: add envtest case for KongTarget (#712)
Browse files Browse the repository at this point in the history
* test: add envtest case for KongTarget

* add wait for confirming target deleted
  • Loading branch information
randmonkey authored Oct 8, 2024
1 parent 15fce4a commit b42d932
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 0 deletions.
142 changes: 142 additions & 0 deletions test/envtest/konnect_entities_target_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package envtest

import (
"context"
"testing"

sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components"
sdkkonnectops "github.com/Kong/sdk-konnect-go/models/operations"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kong/gateway-operator/controller/konnect"
"github.com/kong/gateway-operator/controller/konnect/ops"
"github.com/kong/gateway-operator/modules/manager/scheme"
"github.com/kong/gateway-operator/test/helpers/deploy"

configurationv1alpha1 "github.com/kong/kubernetes-configuration/api/configuration/v1alpha1"
)

func TestKongTarget(t *testing.T) {
t.Parallel()
ctx, cancel := Context(t, context.Background())
defer cancel()
cfg, ns := Setup(t, ctx, scheme.Get())

t.Log("Setting up the manager with reconcilers")
mgr, logs := NewManager(t, ctx, cfg, scheme.Get())
factory := ops.NewMockSDKFactory(t)
sdk := factory.SDK
StartReconcilers(ctx, t, mgr, logs,
konnect.NewKonnectEntityReconciler(factory, false, mgr.GetClient(),
konnect.WithKonnectEntitySyncPeriod[configurationv1alpha1.KongTarget](konnectInfiniteSyncTime),
),
)

t.Log("Setting up clients")
cl, err := client.NewWithWatch(mgr.GetConfig(), client.Options{
Scheme: scheme.Get(),
})
require.NoError(t, err)
clientNamespaced := client.NewNamespacedClient(mgr.GetClient(), ns.Name)

t.Log("Creating KonnectAPIAuthConfiguration and KonnectGatewayControlPlane")
apiAuth := deploy.KonnectAPIAuthConfigurationWithProgrammed(t, ctx, clientNamespaced)
cp := deploy.KonnectGatewayControlPlaneWithID(t, ctx, clientNamespaced, apiAuth)

t.Run("adding, patching and deleting KongTarget", func(t *testing.T) {
const (
upstreamID = "kup-12345"
targetID = "target-12345"
targetHost = "example.com"
targetWeight = 100
)

t.Log("Creating a KongUpstream and setting it to programmed")
upstream := deploy.KongUpstreamAttachedToCP(t, ctx, clientNamespaced, cp)
updateKongUpstreamStatusWithProgrammed(t, ctx, clientNamespaced, upstream, upstreamID, cp.GetKonnectID())

t.Log("Setting up a watch for KongTarget events")
w := setupWatch[configurationv1alpha1.KongTargetList](t, ctx, cl, client.InNamespace(ns.Name))

t.Log("Setting up SDK expectations on Target creation")
sdk.TargetsSDK.EXPECT().CreateTargetWithUpstream(
mock.Anything,
mock.MatchedBy(func(req sdkkonnectops.CreateTargetWithUpstreamRequest) bool {
return *req.TargetWithoutParents.Target == targetHost && *req.TargetWithoutParents.Weight == int64(targetWeight)
}),
).Return(&sdkkonnectops.CreateTargetWithUpstreamResponse{
Target: &sdkkonnectcomp.Target{
ID: lo.ToPtr(targetID),
},
}, nil)

t.Log("Creating a KongTarget")
createdTarget := deploy.KongTargetAttachedToUpstream(t, ctx, clientNamespaced, upstream,
func(obj client.Object) {
kt := obj.(*configurationv1alpha1.KongTarget)
kt.Spec.KongTargetAPISpec.Target = targetHost
kt.Spec.KongTargetAPISpec.Weight = targetWeight
},
)
t.Log("Checking SDK KongTarget operations")
require.EventuallyWithT(t, func(c *assert.CollectT) {
assert.True(c, factory.SDK.TargetsSDK.AssertExpectations(t))
}, waitTime, tickTime)

t.Log("Waiting for Target to be programmed and get Konnect ID")
watchFor(t, ctx, w, watch.Modified, func(kt *configurationv1alpha1.KongTarget) bool {
return kt.GetKonnectID() == targetID && lo.ContainsBy(kt.Status.Conditions,
func(c metav1.Condition) bool {
return c.Type == "Programmed" && c.Status == metav1.ConditionTrue
})
}, "KongTarget didn't get Programmed status condition or didn't get the correct (target-12345) Konnect ID assigned")

t.Log("Setting up SDK expectations on Target update")
sdk.TargetsSDK.EXPECT().UpsertTargetWithUpstream(
mock.Anything,
mock.MatchedBy(func(req sdkkonnectops.UpsertTargetWithUpstreamRequest) bool {
return req.TargetID == targetID && *req.TargetWithoutParents.Weight == int64(200)
}),
).Return(&sdkkonnectops.UpsertTargetWithUpstreamResponse{}, nil)

t.Log("Patching KongTarget")
targetToPatch := createdTarget.DeepCopy()
targetToPatch.Spec.Weight = 200
require.NoError(t, clientNamespaced.Patch(ctx, targetToPatch, client.MergeFrom(createdTarget)))

t.Log("Waiting for Target to be updated in the SDK")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.True(c, factory.SDK.TargetsSDK.AssertExpectations(t))
}, waitTime, tickTime)

t.Log("Setting up SDK expectations on Target deletion")
sdk.TargetsSDK.EXPECT().DeleteTargetWithUpstream(
mock.Anything,
mock.MatchedBy(func(req sdkkonnectops.DeleteTargetWithUpstreamRequest) bool {
return req.TargetID == targetID
}),
).Return(&sdkkonnectops.DeleteTargetWithUpstreamResponse{}, nil)

t.Log("Deleting KongTarget")
require.NoError(t, clientNamespaced.Delete(ctx, createdTarget))

t.Log("Waiting for KongTarget to disappear")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
err := clientNamespaced.Get(ctx, client.ObjectKeyFromObject(createdTarget), createdTarget)
assert.True(c, err != nil && k8serrors.IsNotFound(err))
}, waitTime, tickTime)

t.Log("Waiting for Target to be deleted in the SDK")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.True(c, factory.SDK.TargetsSDK.AssertExpectations(t))
}, waitTime, tickTime)

})
}
18 changes: 18 additions & 0 deletions test/envtest/update_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@ func updateKongKeySetStatusWithProgrammed(
require.NoError(t, cl.Status().Update(ctx, obj))
}

func updateKongUpstreamStatusWithProgrammed(
t *testing.T,
ctx context.Context,
cl client.Client,
obj *configurationv1alpha1.KongUpstream,
id, cpID string,
) {
obj.Status.Konnect = &konnectv1alpha1.KonnectEntityStatusWithControlPlaneRef{
ControlPlaneID: cpID,
KonnectEntityStatus: konnectEntityStatus(id),
}
obj.Status.Conditions = []metav1.Condition{
programmedCondition(obj.GetGeneration()),
}

require.NoError(t, cl.Status().Update(ctx, obj))
}

func konnectEntityStatus(id string) konnectv1alpha1.KonnectEntityStatus {
return konnectv1alpha1.KonnectEntityStatus{
ID: id,
Expand Down

0 comments on commit b42d932

Please sign in to comment.