1/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package testing
18
19import (
20	"fmt"
21	"path"
22	"strings"
23
24	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25	"k8s.io/apimachinery/pkg/fields"
26	"k8s.io/apimachinery/pkg/labels"
27	"k8s.io/apimachinery/pkg/runtime"
28	"k8s.io/apimachinery/pkg/runtime/schema"
29	"k8s.io/apimachinery/pkg/types"
30)
31
32func NewRootGetAction(resource schema.GroupVersionResource, name string) GetActionImpl {
33	action := GetActionImpl{}
34	action.Verb = "get"
35	action.Resource = resource
36	action.Name = name
37
38	return action
39}
40
41func NewGetAction(resource schema.GroupVersionResource, namespace, name string) GetActionImpl {
42	action := GetActionImpl{}
43	action.Verb = "get"
44	action.Resource = resource
45	action.Namespace = namespace
46	action.Name = name
47
48	return action
49}
50
51func NewGetSubresourceAction(resource schema.GroupVersionResource, namespace, subresource, name string) GetActionImpl {
52	action := GetActionImpl{}
53	action.Verb = "get"
54	action.Resource = resource
55	action.Subresource = subresource
56	action.Namespace = namespace
57	action.Name = name
58
59	return action
60}
61
62func NewRootGetSubresourceAction(resource schema.GroupVersionResource, subresource, name string) GetActionImpl {
63	action := GetActionImpl{}
64	action.Verb = "get"
65	action.Resource = resource
66	action.Subresource = subresource
67	action.Name = name
68
69	return action
70}
71
72func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl {
73	action := ListActionImpl{}
74	action.Verb = "list"
75	action.Resource = resource
76	action.Kind = kind
77	labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
78	action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
79
80	return action
81}
82
83func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl {
84	action := ListActionImpl{}
85	action.Verb = "list"
86	action.Resource = resource
87	action.Kind = kind
88	action.Namespace = namespace
89	labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
90	action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
91
92	return action
93}
94
95func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl {
96	action := CreateActionImpl{}
97	action.Verb = "create"
98	action.Resource = resource
99	action.Object = object
100
101	return action
102}
103
104func NewCreateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) CreateActionImpl {
105	action := CreateActionImpl{}
106	action.Verb = "create"
107	action.Resource = resource
108	action.Namespace = namespace
109	action.Object = object
110
111	return action
112}
113
114func NewRootCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource string, object runtime.Object) CreateActionImpl {
115	action := CreateActionImpl{}
116	action.Verb = "create"
117	action.Resource = resource
118	action.Subresource = subresource
119	action.Name = name
120	action.Object = object
121
122	return action
123}
124
125func NewCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource, namespace string, object runtime.Object) CreateActionImpl {
126	action := CreateActionImpl{}
127	action.Verb = "create"
128	action.Resource = resource
129	action.Namespace = namespace
130	action.Subresource = subresource
131	action.Name = name
132	action.Object = object
133
134	return action
135}
136
137func NewRootUpdateAction(resource schema.GroupVersionResource, object runtime.Object) UpdateActionImpl {
138	action := UpdateActionImpl{}
139	action.Verb = "update"
140	action.Resource = resource
141	action.Object = object
142
143	return action
144}
145
146func NewUpdateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) UpdateActionImpl {
147	action := UpdateActionImpl{}
148	action.Verb = "update"
149	action.Resource = resource
150	action.Namespace = namespace
151	action.Object = object
152
153	return action
154}
155
156func NewRootPatchAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte) PatchActionImpl {
157	action := PatchActionImpl{}
158	action.Verb = "patch"
159	action.Resource = resource
160	action.Name = name
161	action.PatchType = pt
162	action.Patch = patch
163
164	return action
165}
166
167func NewPatchAction(resource schema.GroupVersionResource, namespace string, name string, pt types.PatchType, patch []byte) PatchActionImpl {
168	action := PatchActionImpl{}
169	action.Verb = "patch"
170	action.Resource = resource
171	action.Namespace = namespace
172	action.Name = name
173	action.PatchType = pt
174	action.Patch = patch
175
176	return action
177}
178
179func NewRootPatchSubresourceAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl {
180	action := PatchActionImpl{}
181	action.Verb = "patch"
182	action.Resource = resource
183	action.Subresource = path.Join(subresources...)
184	action.Name = name
185	action.PatchType = pt
186	action.Patch = patch
187
188	return action
189}
190
191func NewPatchSubresourceAction(resource schema.GroupVersionResource, namespace, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl {
192	action := PatchActionImpl{}
193	action.Verb = "patch"
194	action.Resource = resource
195	action.Subresource = path.Join(subresources...)
196	action.Namespace = namespace
197	action.Name = name
198	action.PatchType = pt
199	action.Patch = patch
200
201	return action
202}
203
204func NewRootUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, object runtime.Object) UpdateActionImpl {
205	action := UpdateActionImpl{}
206	action.Verb = "update"
207	action.Resource = resource
208	action.Subresource = subresource
209	action.Object = object
210
211	return action
212}
213func NewUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, namespace string, object runtime.Object) UpdateActionImpl {
214	action := UpdateActionImpl{}
215	action.Verb = "update"
216	action.Resource = resource
217	action.Subresource = subresource
218	action.Namespace = namespace
219	action.Object = object
220
221	return action
222}
223
224func NewRootDeleteAction(resource schema.GroupVersionResource, name string) DeleteActionImpl {
225	action := DeleteActionImpl{}
226	action.Verb = "delete"
227	action.Resource = resource
228	action.Name = name
229
230	return action
231}
232
233func NewRootDeleteSubresourceAction(resource schema.GroupVersionResource, subresource string, name string) DeleteActionImpl {
234	action := DeleteActionImpl{}
235	action.Verb = "delete"
236	action.Resource = resource
237	action.Subresource = subresource
238	action.Name = name
239
240	return action
241}
242
243func NewDeleteAction(resource schema.GroupVersionResource, namespace, name string) DeleteActionImpl {
244	action := DeleteActionImpl{}
245	action.Verb = "delete"
246	action.Resource = resource
247	action.Namespace = namespace
248	action.Name = name
249
250	return action
251}
252
253func NewDeleteSubresourceAction(resource schema.GroupVersionResource, subresource, namespace, name string) DeleteActionImpl {
254	action := DeleteActionImpl{}
255	action.Verb = "delete"
256	action.Resource = resource
257	action.Subresource = subresource
258	action.Namespace = namespace
259	action.Name = name
260
261	return action
262}
263
264func NewRootDeleteCollectionAction(resource schema.GroupVersionResource, opts interface{}) DeleteCollectionActionImpl {
265	action := DeleteCollectionActionImpl{}
266	action.Verb = "delete-collection"
267	action.Resource = resource
268	labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
269	action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
270
271	return action
272}
273
274func NewDeleteCollectionAction(resource schema.GroupVersionResource, namespace string, opts interface{}) DeleteCollectionActionImpl {
275	action := DeleteCollectionActionImpl{}
276	action.Verb = "delete-collection"
277	action.Resource = resource
278	action.Namespace = namespace
279	labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
280	action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
281
282	return action
283}
284
285func NewRootWatchAction(resource schema.GroupVersionResource, opts interface{}) WatchActionImpl {
286	action := WatchActionImpl{}
287	action.Verb = "watch"
288	action.Resource = resource
289	labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts)
290	action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion}
291
292	return action
293}
294
295func ExtractFromListOptions(opts interface{}) (labelSelector labels.Selector, fieldSelector fields.Selector, resourceVersion string) {
296	var err error
297	switch t := opts.(type) {
298	case metav1.ListOptions:
299		labelSelector, err = labels.Parse(t.LabelSelector)
300		if err != nil {
301			panic(fmt.Errorf("invalid selector %q: %v", t.LabelSelector, err))
302		}
303		fieldSelector, err = fields.ParseSelector(t.FieldSelector)
304		if err != nil {
305			panic(fmt.Errorf("invalid selector %q: %v", t.FieldSelector, err))
306		}
307		resourceVersion = t.ResourceVersion
308	default:
309		panic(fmt.Errorf("expect a ListOptions %T", opts))
310	}
311	if labelSelector == nil {
312		labelSelector = labels.Everything()
313	}
314	if fieldSelector == nil {
315		fieldSelector = fields.Everything()
316	}
317	return labelSelector, fieldSelector, resourceVersion
318}
319
320func NewWatchAction(resource schema.GroupVersionResource, namespace string, opts interface{}) WatchActionImpl {
321	action := WatchActionImpl{}
322	action.Verb = "watch"
323	action.Resource = resource
324	action.Namespace = namespace
325	labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts)
326	action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion}
327
328	return action
329}
330
331func NewProxyGetAction(resource schema.GroupVersionResource, namespace, scheme, name, port, path string, params map[string]string) ProxyGetActionImpl {
332	action := ProxyGetActionImpl{}
333	action.Verb = "get"
334	action.Resource = resource
335	action.Namespace = namespace
336	action.Scheme = scheme
337	action.Name = name
338	action.Port = port
339	action.Path = path
340	action.Params = params
341	return action
342}
343
344type ListRestrictions struct {
345	Labels labels.Selector
346	Fields fields.Selector
347}
348type WatchRestrictions struct {
349	Labels          labels.Selector
350	Fields          fields.Selector
351	ResourceVersion string
352}
353
354type Action interface {
355	GetNamespace() string
356	GetVerb() string
357	GetResource() schema.GroupVersionResource
358	GetSubresource() string
359	Matches(verb, resource string) bool
360
361	// DeepCopy is used to copy an action to avoid any risk of accidental mutation.  Most people never need to call this
362	// because the invocation logic deep copies before calls to storage and reactors.
363	DeepCopy() Action
364}
365
366type GenericAction interface {
367	Action
368	GetValue() interface{}
369}
370
371type GetAction interface {
372	Action
373	GetName() string
374}
375
376type ListAction interface {
377	Action
378	GetListRestrictions() ListRestrictions
379}
380
381type CreateAction interface {
382	Action
383	GetObject() runtime.Object
384}
385
386type UpdateAction interface {
387	Action
388	GetObject() runtime.Object
389}
390
391type DeleteAction interface {
392	Action
393	GetName() string
394}
395
396type DeleteCollectionAction interface {
397	Action
398	GetListRestrictions() ListRestrictions
399}
400
401type PatchAction interface {
402	Action
403	GetName() string
404	GetPatchType() types.PatchType
405	GetPatch() []byte
406}
407
408type WatchAction interface {
409	Action
410	GetWatchRestrictions() WatchRestrictions
411}
412
413type ProxyGetAction interface {
414	Action
415	GetScheme() string
416	GetName() string
417	GetPort() string
418	GetPath() string
419	GetParams() map[string]string
420}
421
422type ActionImpl struct {
423	Namespace   string
424	Verb        string
425	Resource    schema.GroupVersionResource
426	Subresource string
427}
428
429func (a ActionImpl) GetNamespace() string {
430	return a.Namespace
431}
432func (a ActionImpl) GetVerb() string {
433	return a.Verb
434}
435func (a ActionImpl) GetResource() schema.GroupVersionResource {
436	return a.Resource
437}
438func (a ActionImpl) GetSubresource() string {
439	return a.Subresource
440}
441func (a ActionImpl) Matches(verb, resource string) bool {
442	return strings.ToLower(verb) == strings.ToLower(a.Verb) &&
443		strings.ToLower(resource) == strings.ToLower(a.Resource.Resource)
444}
445func (a ActionImpl) DeepCopy() Action {
446	ret := a
447	return ret
448}
449
450type GenericActionImpl struct {
451	ActionImpl
452	Value interface{}
453}
454
455func (a GenericActionImpl) GetValue() interface{} {
456	return a.Value
457}
458
459func (a GenericActionImpl) DeepCopy() Action {
460	return GenericActionImpl{
461		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
462		// TODO this is wrong, but no worse than before
463		Value: a.Value,
464	}
465}
466
467type GetActionImpl struct {
468	ActionImpl
469	Name string
470}
471
472func (a GetActionImpl) GetName() string {
473	return a.Name
474}
475
476func (a GetActionImpl) DeepCopy() Action {
477	return GetActionImpl{
478		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
479		Name:       a.Name,
480	}
481}
482
483type ListActionImpl struct {
484	ActionImpl
485	Kind             schema.GroupVersionKind
486	Name             string
487	ListRestrictions ListRestrictions
488}
489
490func (a ListActionImpl) GetKind() schema.GroupVersionKind {
491	return a.Kind
492}
493
494func (a ListActionImpl) GetListRestrictions() ListRestrictions {
495	return a.ListRestrictions
496}
497
498func (a ListActionImpl) DeepCopy() Action {
499	return ListActionImpl{
500		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
501		Kind:       a.Kind,
502		Name:       a.Name,
503		ListRestrictions: ListRestrictions{
504			Labels: a.ListRestrictions.Labels.DeepCopySelector(),
505			Fields: a.ListRestrictions.Fields.DeepCopySelector(),
506		},
507	}
508}
509
510type CreateActionImpl struct {
511	ActionImpl
512	Name   string
513	Object runtime.Object
514}
515
516func (a CreateActionImpl) GetObject() runtime.Object {
517	return a.Object
518}
519
520func (a CreateActionImpl) DeepCopy() Action {
521	return CreateActionImpl{
522		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
523		Name:       a.Name,
524		Object:     a.Object.DeepCopyObject(),
525	}
526}
527
528type UpdateActionImpl struct {
529	ActionImpl
530	Object runtime.Object
531}
532
533func (a UpdateActionImpl) GetObject() runtime.Object {
534	return a.Object
535}
536
537func (a UpdateActionImpl) DeepCopy() Action {
538	return UpdateActionImpl{
539		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
540		Object:     a.Object.DeepCopyObject(),
541	}
542}
543
544type PatchActionImpl struct {
545	ActionImpl
546	Name      string
547	PatchType types.PatchType
548	Patch     []byte
549}
550
551func (a PatchActionImpl) GetName() string {
552	return a.Name
553}
554
555func (a PatchActionImpl) GetPatch() []byte {
556	return a.Patch
557}
558
559func (a PatchActionImpl) GetPatchType() types.PatchType {
560	return a.PatchType
561}
562
563func (a PatchActionImpl) DeepCopy() Action {
564	patch := make([]byte, len(a.Patch))
565	copy(patch, a.Patch)
566	return PatchActionImpl{
567		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
568		Name:       a.Name,
569		PatchType:  a.PatchType,
570		Patch:      patch,
571	}
572}
573
574type DeleteActionImpl struct {
575	ActionImpl
576	Name string
577}
578
579func (a DeleteActionImpl) GetName() string {
580	return a.Name
581}
582
583func (a DeleteActionImpl) DeepCopy() Action {
584	return DeleteActionImpl{
585		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
586		Name:       a.Name,
587	}
588}
589
590type DeleteCollectionActionImpl struct {
591	ActionImpl
592	ListRestrictions ListRestrictions
593}
594
595func (a DeleteCollectionActionImpl) GetListRestrictions() ListRestrictions {
596	return a.ListRestrictions
597}
598
599func (a DeleteCollectionActionImpl) DeepCopy() Action {
600	return DeleteCollectionActionImpl{
601		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
602		ListRestrictions: ListRestrictions{
603			Labels: a.ListRestrictions.Labels.DeepCopySelector(),
604			Fields: a.ListRestrictions.Fields.DeepCopySelector(),
605		},
606	}
607}
608
609type WatchActionImpl struct {
610	ActionImpl
611	WatchRestrictions WatchRestrictions
612}
613
614func (a WatchActionImpl) GetWatchRestrictions() WatchRestrictions {
615	return a.WatchRestrictions
616}
617
618func (a WatchActionImpl) DeepCopy() Action {
619	return WatchActionImpl{
620		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
621		WatchRestrictions: WatchRestrictions{
622			Labels:          a.WatchRestrictions.Labels.DeepCopySelector(),
623			Fields:          a.WatchRestrictions.Fields.DeepCopySelector(),
624			ResourceVersion: a.WatchRestrictions.ResourceVersion,
625		},
626	}
627}
628
629type ProxyGetActionImpl struct {
630	ActionImpl
631	Scheme string
632	Name   string
633	Port   string
634	Path   string
635	Params map[string]string
636}
637
638func (a ProxyGetActionImpl) GetScheme() string {
639	return a.Scheme
640}
641
642func (a ProxyGetActionImpl) GetName() string {
643	return a.Name
644}
645
646func (a ProxyGetActionImpl) GetPort() string {
647	return a.Port
648}
649
650func (a ProxyGetActionImpl) GetPath() string {
651	return a.Path
652}
653
654func (a ProxyGetActionImpl) GetParams() map[string]string {
655	return a.Params
656}
657
658func (a ProxyGetActionImpl) DeepCopy() Action {
659	params := map[string]string{}
660	for k, v := range a.Params {
661		params[k] = v
662	}
663	return ProxyGetActionImpl{
664		ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
665		Scheme:     a.Scheme,
666		Name:       a.Name,
667		Port:       a.Port,
668		Path:       a.Path,
669		Params:     params,
670	}
671}
672