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
123
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
140
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
160
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