@@ -20,8 +20,359 @@ import (
2020	"testing" 
2121
2222	v1 "k8s.io/api/core/v1" 
23+ 
24+ 	"errors" 
25+ 
26+ 	apps "k8s.io/api/apps/v1" 
27+ 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 
28+ 	"k8s.io/apimachinery/pkg/runtime" 
29+ 	"k8s.io/apimachinery/pkg/runtime/schema" 
30+ 	"k8s.io/apimachinery/pkg/types" 
31+ 	ctrl "sigs.k8s.io/controller-runtime" 
32+ 	"sigs.k8s.io/controller-runtime/pkg/client" 
2333)
2434
35+ type  mockPlugin  struct  {
36+ 	client.Object 
37+ 	image  string 
38+ }
39+ 
40+ func  (m  * mockPlugin ) GetNamespace () string  {
41+ 	return  "default" 
42+ }
43+ 
44+ func  (m  * mockPlugin ) GetObjectKind () schema.ObjectKind  {
45+ 	return  & metav1.TypeMeta {
46+ 		Kind :       "MockPlugin" ,
47+ 		APIVersion : "v1" ,
48+ 	}
49+ }
50+ 
51+ func  (m  * mockPlugin ) GetName () string  {
52+ 	return  "mock" 
53+ }
54+ 
55+ func  (m  * mockPlugin ) GetUID () types.UID  {
56+ 	return  "mock-uid" 
57+ }
58+ 
59+ type  mockController  struct  {
60+ 	updated    bool 
61+ 	statusErr  error 
62+ 	upgrade    bool 
63+ }
64+ 
65+ func  (m  * mockController ) CreateEmptyObject () client.Object  {
66+ 	return  & mockPlugin {}
67+ }
68+ 
69+ func  (m  * mockController ) NewDaemonSet (rawObj  client.Object ) * apps.DaemonSet  {
70+ 	return  & apps.DaemonSet {
71+ 		ObjectMeta : metav1.ObjectMeta {
72+ 			Name :      "mock-ds" ,
73+ 			Namespace : "default" ,
74+ 		},
75+ 		Spec : apps.DaemonSetSpec {
76+ 			Selector : & metav1.LabelSelector {
77+ 				MatchLabels : map [string ]string {"app" : "mock" },
78+ 			},
79+ 			Template : v1.PodTemplateSpec {
80+ 				ObjectMeta : metav1.ObjectMeta {
81+ 					Labels : map [string ]string {"app" : "mock" },
82+ 				},
83+ 				Spec : v1.PodSpec {
84+ 					Containers : []v1.Container {
85+ 						{
86+ 							Name :  "mock" ,
87+ 							Image : "intel/intel-mock-plugin:latest" ,
88+ 						},
89+ 					},
90+ 				},
91+ 			},
92+ 		},
93+ 	}
94+ }
95+ 
96+ func  (m  * mockController ) UpdateDaemonSet (rawObj  client.Object , ds  * apps.DaemonSet ) (updated  bool ) {
97+ 	return  m .updated 
98+ }
99+ 
100+ func  (m  * mockController ) UpdateStatus (rawObj  client.Object , ds  * apps.DaemonSet , messages  []string ) (updated  bool , err  error ) {
101+ 	if  m .statusErr  !=  nil  {
102+ 		return  false , m .statusErr 
103+ 	}
104+ 
105+ 	return  true , nil 
106+ }
107+ 
108+ func  (m  * mockController ) Upgrade (ctx  context.Context , obj  client.Object ) bool  {
109+ 	return  m .upgrade 
110+ }
111+ 
112+ type  fakeStatusWriter  struct {}
113+ 
114+ func  (f  * fakeStatusWriter ) Create (ctx  context.Context , obj  client.Object , obj2  client.Object , opts  ... client.SubResourceCreateOption ) error  {
115+ 	return  nil 
116+ }
117+ func  (f  * fakeStatusWriter ) Update (ctx  context.Context , obj  client.Object , opts  ... client.SubResourceUpdateOption ) error  {
118+ 	return  nil 
119+ }
120+ func  (f  * fakeStatusWriter ) Patch (ctx  context.Context , obj  client.Object , patch  client.Patch , opts  ... client.SubResourcePatchOption ) error  {
121+ 	return  nil 
122+ }
123+ func  (f  * fakeStatusWriter ) Status () client.StatusWriter  {
124+ 	return  f 
125+ }
126+ 
127+ type  fakeClient  struct  {
128+ 	client.Client 
129+ 	client.StatusWriter 
130+ 	createCalled  bool 
131+ 	getErr        error 
132+ 	listErr       error 
133+ 	updateErr     error 
134+ 	createErr     error 
135+ 	statusErr     error 
136+ 	objects       map [string ]client.Object 
137+ 	ds            []* apps.DaemonSet 
138+ 	pods          []* v1.Pod 
139+ }
140+ 
141+ func  (f  * fakeClient ) Get (ctx  context.Context , key  client.ObjectKey , obj  client.Object , opts  ... client.GetOption ) error  {
142+ 	if  f .getErr  !=  nil  {
143+ 		return  f .getErr 
144+ 	}
145+ 
146+ 	return  nil 
147+ }
148+ func  (f  * fakeClient ) List (ctx  context.Context , list  client.ObjectList , opts  ... client.ListOption ) error  {
149+ 	if  f .listErr  !=  nil  {
150+ 		return  f .listErr 
151+ 	}
152+ 	switch  l  :=  list .(type ) {
153+ 	case  * apps.DaemonSetList :
154+ 		l .Items  =  []apps.DaemonSet {}
155+ 
156+ 		for  _ , ds  :=  range  f .ds  {
157+ 			l .Items  =  append (l .Items , * ds )
158+ 		}
159+ 	case  * v1.PodList :
160+ 		l .Items  =  []v1.Pod {}
161+ 
162+ 		for  _ , pod  :=  range  f .pods  {
163+ 			l .Items  =  append (l .Items , * pod )
164+ 		}
165+ 	}
166+ 	return  nil 
167+ }
168+ func  (f  * fakeClient ) Update (ctx  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
169+ 	return  f .updateErr 
170+ }
171+ func  (f  * fakeClient ) Create (ctx  context.Context , obj  client.Object , opts  ... client.CreateOption ) error  {
172+ 	f .createCalled  =  true 
173+ 	return  f .createErr 
174+ }
175+ func  (f  * fakeClient ) Patch (ctx  context.Context , obj  client.Object , patch  client.Patch , opts  ... client.PatchOption ) error  {
176+ 	return  nil 
177+ }
178+ func  (f  * fakeClient ) Delete (ctx  context.Context , obj  client.Object , opts  ... client.DeleteOption ) error  {
179+ 	return  nil 
180+ }
181+ func  (f  * fakeClient ) UpdateStatus (ctx  context.Context , obj  client.Object , opts  ... client.UpdateOption ) error  {
182+ 	return  f .statusErr 
183+ }
184+ func  (f  * fakeClient ) Status () client.StatusWriter  {
185+ 	return  f .StatusWriter 
186+ }
187+ func  (f  * fakeClient ) Scheme () * runtime.Scheme  {
188+ 	s  :=  runtime .NewScheme ()
189+ 	s .AddKnownTypeWithName (schema.GroupVersionKind {
190+ 		Group :   "deviceplugin.intel.com" ,
191+ 		Version : "v1" ,
192+ 		Kind :    "MockPlugin" ,
193+ 	}, & mockPlugin {})
194+ 
195+ 	return  s 
196+ }
197+ 
198+ func  fillDaemonSets () []* apps.DaemonSet  {
199+ 	return  []* apps.DaemonSet {
200+ 		{
201+ 			ObjectMeta : metav1.ObjectMeta {
202+ 				Name :      "mock-ds" ,
203+ 				Namespace : "default" ,
204+ 			},
205+ 			Spec : apps.DaemonSetSpec {
206+ 				Selector : & metav1.LabelSelector {
207+ 					MatchLabels : map [string ]string {"app" : "mock" },
208+ 				},
209+ 				Template : v1.PodTemplateSpec {
210+ 					ObjectMeta : metav1.ObjectMeta {
211+ 						Labels : map [string ]string {"app" : "mock" },
212+ 					},
213+ 					Spec : v1.PodSpec {
214+ 						Containers : []v1.Container {
215+ 							{
216+ 								Name :  "mock" ,
217+ 								Image : "intel/intel-mock-plugin:latest" ,
218+ 							},
219+ 						},
220+ 					},
221+ 				},
222+ 			},
223+ 		},
224+ 	}
225+ }
226+ 
227+ func  fillPods () []* v1.Pod  {
228+ 	return  []* v1.Pod {
229+ 		{
230+ 			ObjectMeta : metav1.ObjectMeta {
231+ 				Name :      "mock-pod" ,
232+ 				Namespace : "default" ,
233+ 				OwnerReferences : []metav1.OwnerReference {
234+ 					{
235+ 						APIVersion : "apps/v1" ,
236+ 						Kind :       "DaemonSet" ,
237+ 						Name :       "mock-ds" ,
238+ 						UID :        "mock-uid" ,
239+ 					},
240+ 				},
241+ 			},
242+ 			Spec : v1.PodSpec {
243+ 				NodeName : "node1" ,
244+ 				Containers : []v1.Container {
245+ 					{
246+ 						Name :  "mock" ,
247+ 						Image : "intel/intel-mock-plugin:latest" ,
248+ 					},
249+ 				},
250+ 			},
251+ 		},
252+ 	}
253+ }
254+ 
255+ func  TestReconciler_Reconcile_CreateDaemonSet (t  * testing.T ) {
256+ 	controller  :=  & mockController {}
257+ 	c  :=  & fakeClient {
258+ 		StatusWriter : & fakeStatusWriter {},
259+ 		ds :           []* apps.DaemonSet {},
260+ 	}
261+ 	r  :=  & reconciler {
262+ 		controller : controller ,
263+ 		Client :     c ,
264+ 		scheme :     c .Scheme (),
265+ 		pluginKind : "MockPlugin" ,
266+ 		ownerKey :   "owner" ,
267+ 	}
268+ 	req  :=  ctrl.Request {NamespacedName : types.NamespacedName {Name : "mock" , Namespace : "default" }}
269+ 
270+ 	res , err  :=  r .Reconcile (context .Background (), req )
271+ 	if  err  !=  nil  {
272+ 		t .Errorf ("expected no error, got %v" , err )
273+ 	}
274+ 	if  res  !=  (ctrl.Result {}) {
275+ 		t .Errorf ("expected empty result, got %v" , res )
276+ 	}
277+ 	if  c .createCalled  ==  false  {
278+ 		t .Error ("expected create to be called, but it was not" )
279+ 	}
280+ }
281+ 
282+ func  TestReconciler_Reconcile_UpdateDaemonSetAndStatus (t  * testing.T ) {
283+ 	controller  :=  & mockController {
284+ 		updated : true ,
285+ 		upgrade : false ,
286+ 	}
287+ 	c  :=  & fakeClient {
288+ 		StatusWriter : & fakeStatusWriter {},
289+ 		ds :           fillDaemonSets (),
290+ 		pods :         fillPods (),
291+ 	}
292+ 	r  :=  & reconciler {
293+ 		controller : controller ,
294+ 		Client :     c ,
295+ 		scheme :     c .Scheme (),
296+ 		pluginKind : "MockPlugin" ,
297+ 		ownerKey :   "owner" ,
298+ 	}
299+ 	req  :=  ctrl.Request {NamespacedName : client.ObjectKey {Name : "mock" , Namespace : "default" }}
300+ 
301+ 	res , err  :=  r .Reconcile (context .Background (), req )
302+ 	if  err  !=  nil  {
303+ 		t .Errorf ("expected no error, got %v" , err )
304+ 	}
305+ 	if  res  !=  (ctrl.Result {}) {
306+ 		t .Errorf ("expected empty result, got %v" , res )
307+ 	}
308+ }
309+ 
310+ func  TestReconciler_Reconcile_GetError (t  * testing.T ) {
311+ 	controller  :=  & mockController {}
312+ 	c  :=  & fakeClient {
313+ 		getErr :       errors .New ("get error" ),
314+ 		StatusWriter : & fakeStatusWriter {},
315+ 	}
316+ 	r  :=  & reconciler {
317+ 		controller : controller ,
318+ 		Client :     c ,
319+ 		scheme :     c .Scheme (),
320+ 		pluginKind : "MockPlugin" ,
321+ 		ownerKey :   "owner" ,
322+ 	}
323+ 	req  :=  ctrl.Request {NamespacedName : client.ObjectKey {Name : "mock" , Namespace : "default" }}
324+ 
325+ 	_ , err  :=  r .Reconcile (context .Background (), req )
326+ 	if  err  ==  nil  ||  err .Error () !=  "get error"  {
327+ 		t .Errorf ("expected get error, got %v" , err )
328+ 	}
329+ }
330+ 
331+ func  TestReconciler_Reconcile_ListError (t  * testing.T ) {
332+ 	controller  :=  & mockController {}
333+ 	c  :=  & fakeClient {
334+ 		listErr :      errors .New ("list error" ),
335+ 		StatusWriter : & fakeStatusWriter {},
336+ 	}
337+ 	r  :=  & reconciler {
338+ 		controller : controller ,
339+ 		Client :     c ,
340+ 		scheme :     c .Scheme (),
341+ 		pluginKind : "MockPlugin" ,
342+ 		ownerKey :   "owner" ,
343+ 	}
344+ 	req  :=  ctrl.Request {NamespacedName : client.ObjectKey {Name : "mock" , Namespace : "default" }}
345+ 
346+ 	_ , err  :=  r .Reconcile (context .Background (), req )
347+ 	if  err  ==  nil  ||  err .Error () !=  "list error"  {
348+ 		t .Errorf ("expected list error, got %v" , err )
349+ 	}
350+ }
351+ 
352+ func  TestReconciler_Reconcile_UpdateStatusError (t  * testing.T ) {
353+ 	controller  :=  & mockController {
354+ 		statusErr : errors .New ("status update error" ),
355+ 	}
356+ 	c  :=  & fakeClient {
357+ 		StatusWriter : & fakeStatusWriter {},
358+ 		ds :           fillDaemonSets (),
359+ 		pods :         fillPods (),
360+ 	}
361+ 	r  :=  & reconciler {
362+ 		controller : controller ,
363+ 		Client :     c ,
364+ 		scheme :     c .Scheme (),
365+ 		pluginKind : "MockPlugin" ,
366+ 		ownerKey :   "owner" ,
367+ 	}
368+ 	req  :=  ctrl.Request {NamespacedName : client.ObjectKey {Name : "mock" , Namespace : "default" }}
369+ 
370+ 	_ , err  :=  r .Reconcile (context .Background (), req )
371+ 	if  err  ==  nil  ||  err .Error () !=  "status update error"  {
372+ 		t .Errorf ("expected status update error, got %v" , err )
373+ 	}
374+ }
375+ 
25376func  TestUpgrade (test  * testing.T ) {
26377	image  :=  "intel/intel-dsa-plugin" 
27378	initimage  :=  "intel/intel-idxd-config-initcontainer" 
0 commit comments