package info_test import ( "testing" "time" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client/fake" "edge-infra.dev/pkg/edge/info" fakeinfo "edge-infra.dev/pkg/edge/info/fake" "edge-infra.dev/pkg/lib/logging" "edge-infra.dev/test/f2" ) var ( waitForCallbackFunction = 200 * time.Millisecond ) func TestWatchFunctions(t *testing.T) { feature := f2.NewFeature("Test Watch Functions"). Test("OnConfigMapUpdate", func(ctx f2.Context, t *testing.T) f2.Context { cl := fake.NewClientBuilder().Build() updatedStoreName := "foo1" configMap := fakeinfo.GetEdgeInfoConfigMap() // Create an expected cm so we can use it to assert in the OnConfigMapUpdate function. // It matches the cm that is updated later in the test after we read it back. expectedUpdatedCM := fakeinfo.GetEdgeInfoConfigMap() expectedUpdatedCM.Data[info.StoreName] = updatedStoreName // create ConfigMap watch callCount := 0 logger := logging.NewLogger().WithName("TestOnConfigMapUpdate") watch, err := info.OnConfigMapUpdate(ctx, cl, logger, func(i *info.EdgeInfo) { assert.NotNil(t, configMap) if callCount == 0 { assert.Equal(t, info.FromConfigMap(configMap), i) } else { assert.Equal(t, info.FromConfigMap(expectedUpdatedCM), i) } callCount++ }) assert.NoError(t, err) defer watch.Stop() assert.NoError(t, cl.Create(ctx, configMap)) time.Sleep(waitForCallbackFunction) // wait for async call // We need to read the configmap after the cm create to be able to update it, // otherwise it will fail with Operation cannot be fulfilled on configmaps "edge-info": object was modified // due to not having the most recent object data. readCM := corev1.ConfigMap{} err = cl.Get(ctx, types.NamespacedName{ Name: info.EdgeConfigMapName, Namespace: info.EdgeConfigMapNS, }, &readCM) assert.NoError(t, err) readCM.Data[info.StoreName] = updatedStoreName assert.NoError(t, cl.Update(ctx, &readCM)) time.Sleep(waitForCallbackFunction) assert.Equal(t, 2, callCount) return ctx }). Test("OnConfigMapUpdateInvalid", func(ctx f2.Context, t *testing.T) f2.Context { cl := fake.NewClientBuilder().Build() configMap := fakeinfo.GetEdgeInfoConfigMap() // create ConfigMap watch callCount := 0 logger := logging.NewLogger().WithName("TestOnConfigMapUpdateInvalid") watch, err := info.OnConfigMapUpdate(ctx, cl, logger, func(i *info.EdgeInfo) { assert.NotNil(t, configMap) assert.Equal(t, info.FromConfigMap(configMap), i) callCount++ }) assert.NoError(t, err) defer watch.Stop() assert.NoError(t, cl.Create(ctx, configMap)) time.Sleep(waitForCallbackFunction) // wait for async call readCM := corev1.ConfigMap{} err = cl.Get(ctx, types.NamespacedName{ Name: info.EdgeConfigMapName, Namespace: info.EdgeConfigMapNS, }, &readCM) assert.NoError(t, err) delete(readCM.Data, info.StoreName) assert.NoError(t, cl.Update(ctx, &readCM)) time.Sleep(waitForCallbackFunction) assert.Equal(t, 1, callCount) return ctx }). Test("OnConfigMapUpdateFilterMatchAll", func(ctx f2.Context, t *testing.T) f2.Context { // nolint: dupl cl := fake.NewClientBuilder().Build() configMap := fakeinfo.GetEdgeInfoConfigMap() updatedConfigmap := fakeinfo.GetEdgeInfoConfigMap() newStoreName := "updated-store-name" newCluster := "new-id" updatedConfigmap.Data[info.StoreName] = newStoreName updatedConfigmap.Data[info.ClusterEdgeID] = newCluster // create ConfigMap watch callCount := 0 logger := logging.NewLogger().WithName("TestOnConfigMapUpdateFilterMatchAll") watch, err := info.OnConfigMapUpdate(ctx, cl, logger, func(i *info.EdgeInfo) { assert.NotNil(t, configMap) if callCount == 0 { assert.Equal(t, info.FromConfigMap(configMap), i) } else { assert.Equal(t, info.FromConfigMap(updatedConfigmap), i) } callCount++ }, info.StoreName, info.ClusterEdgeID) assert.NoError(t, err) defer watch.Stop() assert.NoError(t, cl.Create(ctx, configMap)) time.Sleep(waitForCallbackFunction) readCM := corev1.ConfigMap{} err = cl.Get(ctx, types.NamespacedName{ Name: info.EdgeConfigMapName, Namespace: info.EdgeConfigMapNS, }, &readCM) assert.NoError(t, err) readCM.Data[info.StoreName] = newStoreName readCM.Data[info.ClusterEdgeID] = newCluster assert.NoError(t, cl.Update(ctx, &readCM)) time.Sleep(waitForCallbackFunction) assert.Equal(t, 2, callCount) return ctx }). Test("OnConfigMapUpdateFilterMatchOne", func(ctx f2.Context, t *testing.T) f2.Context { // nolint: dupl cl := fake.NewClientBuilder().Build() configMap := fakeinfo.GetEdgeInfoConfigMap() updatedConfigmap := fakeinfo.GetEdgeInfoConfigMap() newStore := "foo3" newLoc := "new-location" updatedConfigmap.Data[info.StoreName] = newStore updatedConfigmap.Data[info.K8sClusterLocation] = newLoc // create ConfigMap watch callCount := 0 logger := logging.NewLogger().WithName("TestOnConfigMapUpdateFilterMatchOne") watch, err := info.OnConfigMapUpdate(ctx, cl, logger, func(i *info.EdgeInfo) { assert.NotNil(t, configMap) if callCount == 0 { assert.Equal(t, info.FromConfigMap(configMap), i) } else { assert.Equal(t, info.FromConfigMap(updatedConfigmap), i) } callCount++ }, info.StoreName, info.ClusterEdgeID) assert.NoError(t, err) defer watch.Stop() assert.NoError(t, cl.Create(ctx, configMap)) time.Sleep(waitForCallbackFunction) readCM := corev1.ConfigMap{} err = cl.Get(ctx, types.NamespacedName{ Name: info.EdgeConfigMapName, Namespace: info.EdgeConfigMapNS, }, &readCM) assert.NoError(t, err) readCM.Data[info.StoreName] = newStore readCM.Data[info.K8sClusterLocation] = newLoc assert.NoError(t, cl.Update(ctx, &readCM)) time.Sleep(waitForCallbackFunction) assert.Equal(t, 2, callCount) return ctx }). Test("OnConfigMapUpdateFilterMatchNone", func(ctx f2.Context, t *testing.T) f2.Context { cl := fake.NewClientBuilder().Build() configMap := fakeinfo.GetEdgeInfoConfigMap() updatedConfigmap := fakeinfo.GetEdgeInfoConfigMap() storeName := "foo4" updatedConfigmap.Data[info.StoreName] = storeName // create ConfigMap watch callCount := 0 logger := logging.NewLogger().WithName("TestOnConfigMapUpdateFilterMatchNone") watch, err := info.OnConfigMapUpdate(ctx, cl, logger, func(i *info.EdgeInfo) { assert.NotNil(t, configMap) assert.Equal(t, info.FromConfigMap(configMap), i) callCount++ }, info.ClusterEdgeID, info.ProjectID) assert.NoError(t, err) defer watch.Stop() assert.NoError(t, cl.Create(ctx, configMap)) time.Sleep(waitForCallbackFunction) // wait for async call readCM := corev1.ConfigMap{} err = cl.Get(ctx, types.NamespacedName{ Name: info.EdgeConfigMapName, Namespace: info.EdgeConfigMapNS, }, &readCM) assert.NoError(t, err) readCM.Data[info.StoreName] = storeName assert.NoError(t, cl.Update(ctx, &readCM)) time.Sleep(waitForCallbackFunction) assert.Equal(t, 1, callCount) return ctx }).Feature() f.Test(t, feature) }