...

Source file src/edge-infra.dev/pkg/sds/interlock/topic/cluster/cluster_test.go

Documentation: edge-infra.dev/pkg/sds/interlock/topic/cluster

     1  package cluster
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/go-logr/logr/testr"
     8  	"github.com/spf13/afero"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  	v1 "k8s.io/api/core/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	kruntime "k8s.io/apimachinery/pkg/runtime"
    14  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    15  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    16  	ctrl "sigs.k8s.io/controller-runtime"
    17  	"sigs.k8s.io/controller-runtime/pkg/cache/informertest"
    18  	"sigs.k8s.io/controller-runtime/pkg/client"
    19  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    20  	"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
    21  
    22  	"edge-infra.dev/pkg/edge/info"
    23  	"edge-infra.dev/pkg/sds/interlock/internal/config"
    24  	"edge-infra.dev/pkg/sds/interlock/topic"
    25  	"edge-infra.dev/pkg/sds/interlock/websocket"
    26  	"edge-infra.dev/pkg/sds/lib/k8s/retryclient"
    27  )
    28  
    29  func SetupTestCtx(t *testing.T) context.Context {
    30  	logOptions := testr.Options{
    31  		LogTimestamp: true,
    32  		Verbosity:    -1,
    33  	}
    34  
    35  	ctx := ctrl.LoggerInto(context.Background(), testr.NewWithOptions(t, logOptions))
    36  	return ctx
    37  }
    38  
    39  func getTestConfigMap(t *testing.T, name, namespace string, data map[string]string) *v1.ConfigMap {
    40  	t.Helper()
    41  	return &v1.ConfigMap{
    42  		ObjectMeta: metav1.ObjectMeta{
    43  			Name:      name,
    44  			Namespace: namespace,
    45  		},
    46  		Data: data,
    47  	}
    48  }
    49  
    50  func TestIsEdgeInfoCM(t *testing.T) {
    51  	tests := map[string]struct {
    52  		input interface{}
    53  		want  bool
    54  	}{
    55  		"Invalid": {
    56  			input: struct{}{},
    57  			want:  false,
    58  		},
    59  		"Incorrect_CMName": {
    60  			input: getTestConfigMap(t, "", info.EdgeConfigMapNS, nil),
    61  			want:  false,
    62  		},
    63  		"Incorrect_CMNamespace": {
    64  			input: getTestConfigMap(t, info.EdgeConfigMapName, "", nil),
    65  			want:  false,
    66  		},
    67  		"Correct_CM": {
    68  			input: getTestConfigMap(t, info.EdgeConfigMapName, info.EdgeConfigMapNS, nil),
    69  			want:  true,
    70  		},
    71  	}
    72  
    73  	for name, tc := range tests {
    74  		t.Run(name, func(t *testing.T) {
    75  			got := IsEdgeInfoCM(tc.input)
    76  			assert.Equal(t, tc.want, got)
    77  		})
    78  	}
    79  }
    80  
    81  type testStruct struct {
    82  	state *State
    83  }
    84  
    85  func (t *testStruct) updateState(fn topic.UpdateFunc) error {
    86  	return fn(t.state)
    87  }
    88  
    89  func TestUpdateName(t *testing.T) {
    90  	tests := map[string]struct {
    91  		previousClusterName string
    92  		want                string
    93  	}{
    94  		"NotPreviouslySet": {
    95  			previousClusterName: "",
    96  			want:                "test-name",
    97  		},
    98  		"PreviouslySet": {
    99  			previousClusterName: "previous-name",
   100  			want:                "test-name",
   101  		},
   102  	}
   103  
   104  	for name, tc := range tests {
   105  		t.Run(name, func(t *testing.T) {
   106  			ts := testStruct{&State{Name: tc.previousClusterName}}
   107  			cm := getTestConfigMap(t, "name", "ns", map[string]string{
   108  				"cluster.name": tc.want,
   109  			})
   110  
   111  			updateName(ts.updateState, cm)
   112  
   113  			assert.Equal(t, tc.want, ts.state.Name)
   114  		})
   115  	}
   116  }
   117  
   118  type mockCache struct {
   119  	*informertest.FakeInformers
   120  }
   121  
   122  // integration test for SetupAPIInformers method
   123  // and NameEventHandler OnAdd method
   124  func TestSetupAPIInformersAdd(t *testing.T) {
   125  	testCluster, fakeInformer := newTestClusterWithFakeInformer(t, &State{})
   126  
   127  	cm := getTestConfigMap(t, info.EdgeConfigMapName, info.EdgeConfigMapNS, map[string]string{
   128  		"cluster.name": "test-name",
   129  	})
   130  	fakeInformer.Add(cm)
   131  
   132  	clusterState := testCluster.topic.State()
   133  	state, ok := clusterState.(*State)
   134  	require.True(t, ok)
   135  
   136  	assert.Equal(t, "test-name", state.Name)
   137  }
   138  
   139  // integration test for SetupAPIInformers method
   140  // and NameEventHandler OnUpdate method
   141  func TestSetupAPIInformersUpdate(t *testing.T) {
   142  	testCluster, fakeInformer := newTestClusterWithFakeInformer(t, &State{})
   143  
   144  	oldCM := getTestConfigMap(t, info.EdgeConfigMapName, info.EdgeConfigMapNS, map[string]string{
   145  		"cluster.name": "test-name",
   146  	})
   147  	newCM := getTestConfigMap(t, info.EdgeConfigMapName, info.EdgeConfigMapNS, map[string]string{
   148  		"cluster.name": "new-name",
   149  	})
   150  	fakeInformer.Update(oldCM, newCM)
   151  
   152  	clusterState := testCluster.topic.State()
   153  	state, ok := clusterState.(*State)
   154  	require.True(t, ok)
   155  
   156  	assert.Equal(t, "new-name", state.Name)
   157  }
   158  
   159  // integration test for SetupAPIInformers method
   160  // and NameEventHandler OnDelete method
   161  func TestSetupAPIInformersDelete(t *testing.T) {
   162  	testCluster, fakeInformer := newTestClusterWithFakeInformer(t, &State{"test-name"})
   163  
   164  	cm := getTestConfigMap(t, info.EdgeConfigMapName, info.EdgeConfigMapNS, map[string]string{
   165  		"cluster.name": "test-name",
   166  	})
   167  	fakeInformer.Delete(cm)
   168  
   169  	clusterState := testCluster.topic.State()
   170  	state, ok := clusterState.(*State)
   171  	require.True(t, ok)
   172  
   173  	assert.Equal(t, "test-name", state.Name)
   174  }
   175  
   176  func newTestClusterWithFakeInformer(t *testing.T, initState *State) (*Cluster, *controllertest.FakeInformer) {
   177  	testCfg := config.Config{
   178  		Cache: mockCache{&informertest.FakeInformers{}},
   179  	}
   180  	testCluster := Cluster{
   181  		topic: topic.NewTopic(
   182  			TopicName,
   183  			initState,
   184  			nil,
   185  			websocket.NewManager(),
   186  		),
   187  	}
   188  
   189  	err := testCluster.SetupAPIInformers(context.Background(), &testCfg)
   190  	require.NoError(t, err)
   191  
   192  	informer, err := testCfg.Cache.GetInformer(context.Background(), &v1.ConfigMap{})
   193  	require.NoError(t, err)
   194  
   195  	fakeInformer, ok := informer.(*controllertest.FakeInformer)
   196  	require.True(t, ok)
   197  
   198  	return &testCluster, fakeInformer
   199  }
   200  
   201  func TestNewState(t *testing.T) {
   202  	ei := &info.EdgeInfo{
   203  		BannerName:       "example",
   204  		ProjectID:        "example",
   205  		Store:            "test-cluster",
   206  		Fleet:            "example",
   207  		ClusterType:      "example",
   208  		Location:         "example",
   209  		ForemanProjectID: "example",
   210  		BannerEdgeID:     "example",
   211  		ClusterEdgeID:    "example",
   212  		EdgeAPIEndpoint:  "example",
   213  	}
   214  	cm := ei.ToConfigMap()
   215  
   216  	cli := getFakeKubeClient(cm)
   217  
   218  	cfg := &config.Config{
   219  		Fs:              afero.NewMemMapFs(),
   220  		KubeRetryClient: retryclient.New(cli, cli, retryclient.Config{}),
   221  		Cache:           &informertest.FakeInformers{},
   222  	}
   223  	state, err := newState(SetupTestCtx(t), cfg)
   224  	require.NoError(t, err)
   225  
   226  	assert.Equal(t, "test-cluster", state.Name)
   227  }
   228  
   229  func getFakeKubeClient(initObjs ...client.Object) client.Client {
   230  	return fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(initObjs...).Build()
   231  }
   232  
   233  func createScheme() *kruntime.Scheme {
   234  	scheme := kruntime.NewScheme()
   235  	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
   236  	return scheme
   237  }
   238  

View as plain text