Skip to content

Commit 97ebff8

Browse files
committed
Unit tests for the observer
1 parent 4521d0b commit 97ebff8

File tree

1 file changed

+281
-0
lines changed

1 file changed

+281
-0
lines changed

pkg/observer/observer_test.go

+281
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
package observer
2+
3+
import (
4+
"net/http"
5+
"reflect"
6+
"sort"
7+
"testing"
8+
9+
"github.com/bpineau/katafygio/config"
10+
"github.com/bpineau/katafygio/pkg/controller"
11+
"github.com/bpineau/katafygio/pkg/event"
12+
"github.com/bpineau/katafygio/pkg/log"
13+
14+
appsv1beta2 "k8s.io/api/apps/v1beta2"
15+
corev1 "k8s.io/api/core/v1"
16+
extv1beta1 "k8s.io/api/extensions/v1beta1"
17+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18+
_ "k8s.io/apimachinery/pkg/version"
19+
fakediscovery "k8s.io/client-go/discovery/fake"
20+
fakeclientset "k8s.io/client-go/kubernetes/fake"
21+
"k8s.io/client-go/kubernetes/scheme"
22+
restclient "k8s.io/client-go/rest"
23+
fakerest "k8s.io/client-go/rest/fake"
24+
"k8s.io/client-go/tools/cache"
25+
)
26+
27+
type mockNotifier struct{}
28+
29+
func (m *mockNotifier) Send(ev *event.Notification) {}
30+
func (m *mockNotifier) ReadChan() <-chan event.Notification {
31+
return make(chan event.Notification)
32+
}
33+
34+
type mockCtrl struct{}
35+
36+
func (m *mockCtrl) Start() {}
37+
func (m *mockCtrl) Stop() {}
38+
39+
type mockFactory struct {
40+
names []string
41+
}
42+
43+
func (m *mockFactory) NewController(client cache.ListerWatcher, notifier event.Notifier,
44+
name string, config *config.KfConfig) controller.Interface {
45+
m.names = append(m.names, name)
46+
return &mockCtrl{}
47+
}
48+
49+
var stdVerbs = []string{"list", "get", "watch"}
50+
var emptyExclude = make([]string, 0)
51+
52+
type resTest struct {
53+
title string
54+
resources []*metav1.APIResourceList
55+
exclude []string
56+
expect []string
57+
}
58+
59+
var resourcesTests = []resTest{
60+
61+
{
62+
title: "Normal resource parsing",
63+
exclude: emptyExclude,
64+
expect: []string{"pod", "replicationcontroller", "replicaset"},
65+
resources: []*metav1.APIResourceList{
66+
{
67+
GroupVersion: corev1.SchemeGroupVersion.String(),
68+
APIResources: []metav1.APIResource{
69+
{Name: "pods", Namespaced: true, Kind: "Pod", Verbs: stdVerbs},
70+
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController", Verbs: stdVerbs},
71+
},
72+
},
73+
{
74+
GroupVersion: extv1beta1.SchemeGroupVersion.String(),
75+
APIResources: []metav1.APIResource{
76+
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet", Verbs: stdVerbs},
77+
},
78+
},
79+
},
80+
},
81+
{
82+
title: "Eliminate cohabitations",
83+
exclude: emptyExclude,
84+
expect: []string{"deployment"},
85+
resources: []*metav1.APIResourceList{
86+
{
87+
GroupVersion: appsv1beta2.SchemeGroupVersion.String(),
88+
APIResources: []metav1.APIResource{
89+
{Name: "deployments", Namespaced: true, Kind: "Deployment", Verbs: stdVerbs},
90+
},
91+
},
92+
{
93+
GroupVersion: extv1beta1.SchemeGroupVersion.String(),
94+
APIResources: []metav1.APIResource{
95+
{Name: "deployments", Namespaced: true, Kind: "Deployment", Verbs: stdVerbs},
96+
},
97+
},
98+
},
99+
},
100+
{
101+
title: "Eliminate non listable/getable/watchable",
102+
exclude: emptyExclude,
103+
expect: []string{"bar4"},
104+
resources: []*metav1.APIResourceList{
105+
{
106+
GroupVersion: "foo/v42",
107+
APIResources: []metav1.APIResource{
108+
{Name: "bar1", Namespaced: true, Kind: "Bar1", Verbs: []string{"get"}},
109+
{Name: "bar2", Namespaced: true, Kind: "Bar2", Verbs: []string{"get", "list"}},
110+
{Name: "bar3", Namespaced: true, Kind: "Bar3", Verbs: []string{"watch"}},
111+
{Name: "bar4", Namespaced: true, Kind: "Bar4", Verbs: stdVerbs},
112+
},
113+
},
114+
},
115+
},
116+
117+
{
118+
title: "Eliminate unparsable groups",
119+
exclude: emptyExclude,
120+
expect: []string{"spam1"},
121+
resources: []*metav1.APIResourceList{
122+
{
123+
GroupVersion: "foo/v42",
124+
APIResources: []metav1.APIResource{
125+
{Name: "spam1", Namespaced: true, Kind: "Spam1", Verbs: stdVerbs},
126+
},
127+
},
128+
{
129+
GroupVersion: "foo/bar/baz/v42",
130+
APIResources: []metav1.APIResource{
131+
{Name: "spam2", Namespaced: true, Kind: "Spam2", Verbs: stdVerbs},
132+
},
133+
},
134+
},
135+
},
136+
137+
{
138+
title: "Eliminate subresources",
139+
exclude: emptyExclude,
140+
expect: []string{"pod", "replicationcontroller"},
141+
resources: []*metav1.APIResourceList{
142+
{
143+
GroupVersion: corev1.SchemeGroupVersion.String(),
144+
APIResources: []metav1.APIResource{
145+
{Name: "pods", Namespaced: true, Kind: "Pod", Verbs: stdVerbs},
146+
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController", Verbs: stdVerbs},
147+
{Name: "replicationcontrollers/scale", Namespaced: true, Kind: "Scale", Group: "autoscaling", Version: "v1", Verbs: stdVerbs},
148+
},
149+
},
150+
},
151+
},
152+
153+
{
154+
title: "Eliminate user filtered",
155+
exclude: []string{"bar1", "bar3"},
156+
expect: []string{"bar2", "bar4"},
157+
resources: []*metav1.APIResourceList{
158+
{
159+
GroupVersion: "foo/v42",
160+
APIResources: []metav1.APIResource{
161+
{Name: "bar1", Namespaced: true, Kind: "Bar1", Verbs: stdVerbs},
162+
{Name: "bar2", Namespaced: true, Kind: "Bar2", Verbs: stdVerbs},
163+
{Name: "bar3", Namespaced: true, Kind: "Bar3", Verbs: stdVerbs},
164+
{Name: "bar4", Namespaced: true, Kind: "Bar4", Verbs: stdVerbs},
165+
},
166+
},
167+
},
168+
},
169+
}
170+
171+
func TestObserver(t *testing.T) {
172+
for _, tt := range resourcesTests {
173+
conf := &config.KfConfig{
174+
Client: &restclient.Config{},
175+
Logger: log.New("info", "", "test"),
176+
ExcludeKind: tt.exclude,
177+
}
178+
179+
client := fakeclientset.NewSimpleClientset()
180+
fakeDiscovery, _ := client.Discovery().(*fakediscovery.FakeDiscovery)
181+
fakeDiscovery.Resources = tt.resources
182+
factory := new(mockFactory)
183+
obs := New(conf, &mockNotifier{}, factory)
184+
obs.discovery = fakeDiscovery
185+
obs.Start()
186+
obs.Stop()
187+
188+
sort.Strings(factory.names)
189+
sort.Strings(tt.expect)
190+
if !reflect.DeepEqual(factory.names, tt.expect) {
191+
t.Errorf("%s failed: expected %v actual %v", tt.title, tt.expect, factory.names)
192+
}
193+
}
194+
}
195+
196+
var duplicatesTest = []*metav1.APIResourceList{
197+
{
198+
199+
GroupVersion: corev1.SchemeGroupVersion.String(),
200+
APIResources: []metav1.APIResource{
201+
{Name: "pods", Namespaced: true, Kind: "Pod", Verbs: stdVerbs},
202+
},
203+
},
204+
{
205+
GroupVersion: extv1beta1.SchemeGroupVersion.String(),
206+
APIResources: []metav1.APIResource{
207+
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet", Verbs: stdVerbs},
208+
{Name: "deployments", Namespaced: true, Kind: "Deployment", Verbs: stdVerbs},
209+
},
210+
},
211+
}
212+
213+
func TestObserverDuplicas(t *testing.T) {
214+
conf := &config.KfConfig{
215+
Client: &restclient.Config{},
216+
Logger: log.New("info", "", "test"),
217+
ExcludeKind: make([]string, 0),
218+
ExcludeObject: make([]string, 0),
219+
}
220+
221+
client := fakeclientset.NewSimpleClientset()
222+
fakeDiscovery, _ := client.Discovery().(*fakediscovery.FakeDiscovery)
223+
fakeDiscovery.Resources = duplicatesTest
224+
225+
factory := new(mockFactory)
226+
obs := New(conf, &mockNotifier{}, factory)
227+
obs.discovery = fakeDiscovery
228+
obs.Start()
229+
err := obs.refresh()
230+
if err != nil {
231+
t.Errorf("refresh failed: %v", err)
232+
}
233+
obs.Stop()
234+
235+
expected := []string{"pod", "replicaset", "deployment"}
236+
sort.Strings(factory.names)
237+
sort.Strings(expected)
238+
if !reflect.DeepEqual(factory.names, expected) {
239+
t.Errorf("%s failed: expected %v actual %v", "Eliminate duplicates", expected, factory.names)
240+
}
241+
}
242+
243+
func TestObserverRecoverFromDicoveryFailure(t *testing.T) {
244+
conf := &config.KfConfig{
245+
Client: &restclient.Config{},
246+
Logger: log.New("info", "", "test"),
247+
ExcludeKind: make([]string, 0),
248+
ExcludeObject: make([]string, 0),
249+
}
250+
251+
client := fakeclientset.NewSimpleClientset()
252+
fakeDiscovery, _ := client.Discovery().(*fakediscovery.FakeDiscovery)
253+
fakeDiscovery.Resources = duplicatesTest
254+
255+
fakeClient := &fakerest.RESTClient{
256+
NegotiatedSerializer: scheme.Codecs,
257+
Resp: &http.Response{
258+
StatusCode: http.StatusOK,
259+
},
260+
}
261+
262+
factory := new(mockFactory)
263+
obs := New(conf, &mockNotifier{}, factory)
264+
265+
// failing discovery
266+
obs.discovery.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
267+
obs.Start()
268+
obs.Stop()
269+
270+
// should resume discovery
271+
obs.discovery = fakeDiscovery
272+
obs.Start()
273+
obs.Stop()
274+
275+
expected := []string{"pod", "replicaset", "deployment"}
276+
sort.Strings(factory.names)
277+
sort.Strings(expected)
278+
if !reflect.DeepEqual(factory.names, expected) {
279+
t.Errorf("%s failed: expected %v actual %v", "Recover from failure", expected, factory.names)
280+
}
281+
}

0 commit comments

Comments
 (0)