mirror of https://github.com/knative/pkg.git
				
				
				
			
		
			
				
	
	
		
			177 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2017 The Knative Authors
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package testing
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 
 | |
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	"k8s.io/apimachinery/pkg/runtime"
 | |
| 	"k8s.io/apimachinery/pkg/runtime/schema"
 | |
| 
 | |
| 	"knative.dev/pkg/apis"
 | |
| )
 | |
| 
 | |
| // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | |
| 
 | |
| // Resource is a simple resource that's compatible with our webhook
 | |
| type Resource struct {
 | |
| 	metav1.TypeMeta   `json:",inline"`
 | |
| 	metav1.ObjectMeta `json:"metadata,omitempty"`
 | |
| 
 | |
| 	Spec ResourceSpec `json:"spec,omitempty"`
 | |
| }
 | |
| 
 | |
| // Check that Resource may be validated and defaulted.
 | |
| var _ apis.Validatable = (*Resource)(nil)
 | |
| var _ apis.Defaultable = (*Resource)(nil)
 | |
| var _ apis.Listable = (*Resource)(nil)
 | |
| 
 | |
| // ResourceSpec represents test resource spec.
 | |
| type ResourceSpec struct {
 | |
| 	FieldWithDefault                         string `json:"fieldWithDefault,omitempty"`
 | |
| 	FieldWithContextDefault                  string `json:"fieldWithContextDefault,omitempty"`
 | |
| 	FieldWithValidation                      string `json:"fieldWithValidation,omitempty"`
 | |
| 	FieldThatsImmutable                      string `json:"fieldThatsImmutable,omitempty"`
 | |
| 	FieldThatsImmutableWithDefault           string `json:"fieldThatsImmutableWithDefault,omitempty"`
 | |
| 	FieldForCallbackValidation               string `json:"fieldThatCallbackRejects,omitempty"`
 | |
| 	FieldForCallbackDefaulting               string `json:"fieldForCallbackDefaulting,omitempty"`
 | |
| 	FieldForCallbackDefaultingIsWithinUpdate bool   `json:"fieldForCallbackDefaultingIsWithinUpdate,omitempty"`
 | |
| 	FieldForCallbackDefaultingUsername       string `json:"fieldForCallbackDefaultingUsername,omitempty"`
 | |
| }
 | |
| 
 | |
| // Reject any udpates to this subresource.
 | |
| const disallowedSubresource = "badbadsubresource"
 | |
| 
 | |
| // GetGroupVersionKind returns the GroupVersionKind.
 | |
| func (r *Resource) GetGroupVersionKind() schema.GroupVersionKind {
 | |
| 	return SchemeGroupVersion.WithKind("Resource")
 | |
| }
 | |
| 
 | |
| // GetGroupVersionKindMeta returns the metav1.GroupVersionKind.
 | |
| func (r *Resource) GetGroupVersionKindMeta() metav1.GroupVersionKind {
 | |
| 	gvk := r.GroupVersionKind()
 | |
| 	return metav1.GroupVersionKind{
 | |
| 		Group:   gvk.Group,
 | |
| 		Version: gvk.Version,
 | |
| 		Kind:    gvk.Kind,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // GetUntypedSpec returns the spec of the resource.
 | |
| func (r *Resource) GetUntypedSpec() interface{} {
 | |
| 	return r.Spec
 | |
| }
 | |
| 
 | |
| // SetDefaults sets the defaults on the object.
 | |
| func (r *Resource) SetDefaults(ctx context.Context) {
 | |
| 	r.Spec.SetDefaults(ctx)
 | |
| }
 | |
| 
 | |
| func (r *Resource) Validate(ctx context.Context) *apis.FieldError {
 | |
| 	err := r.Spec.Validate(ctx).ViaField("spec")
 | |
| 
 | |
| 	if apis.IsInUpdate(ctx) {
 | |
| 		original := apis.GetBaseline(ctx).(*Resource)
 | |
| 		err = err.Also(r.CheckImmutableFields(ctx, original))
 | |
| 		err = err.Also(r.CheckAllowedSubresourceUpdate(ctx, original))
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| type onContextKey struct{}
 | |
| 
 | |
| // WithValue returns a WithContext for attaching an OnContext with the given value.
 | |
| func WithValue(ctx context.Context, val string) context.Context {
 | |
| 	return context.WithValue(ctx, onContextKey{}, &OnContext{Value: val})
 | |
| }
 | |
| 
 | |
| // OnContext is a struct for holding a value attached to a context.
 | |
| type OnContext struct {
 | |
| 	Value string
 | |
| }
 | |
| 
 | |
| // SetDefaults sets the defaults on the spec.
 | |
| func (cs *ResourceSpec) SetDefaults(ctx context.Context) {
 | |
| 	if cs.FieldWithDefault == "" {
 | |
| 		cs.FieldWithDefault = "I'm a default."
 | |
| 	}
 | |
| 	if cs.FieldWithContextDefault == "" {
 | |
| 		oc, ok := ctx.Value(onContextKey{}).(*OnContext)
 | |
| 		if ok {
 | |
| 			cs.FieldWithContextDefault = oc.Value
 | |
| 		}
 | |
| 	}
 | |
| 	if cs.FieldThatsImmutableWithDefault == "" {
 | |
| 		cs.FieldThatsImmutableWithDefault = "this is another default value"
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cs *ResourceSpec) Validate(ctx context.Context) *apis.FieldError {
 | |
| 	if cs.FieldWithValidation != "magic value" {
 | |
| 		return apis.ErrInvalidValue(cs.FieldWithValidation, "fieldWithValidation")
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (r *Resource) CheckImmutableFields(ctx context.Context, original *Resource) *apis.FieldError {
 | |
| 	if original.Spec.FieldThatsImmutable != r.Spec.FieldThatsImmutable {
 | |
| 		return &apis.FieldError{
 | |
| 			Message: "Immutable field changed",
 | |
| 			Paths:   []string{"spec.fieldThatsImmutable"},
 | |
| 			Details: fmt.Sprintf("got: %v, want: %v", r.Spec.FieldThatsImmutable,
 | |
| 				original.Spec.FieldThatsImmutable),
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if original.Spec.FieldThatsImmutableWithDefault != r.Spec.FieldThatsImmutableWithDefault {
 | |
| 		return &apis.FieldError{
 | |
| 			Message: "Immutable field changed",
 | |
| 			Paths:   []string{"spec.fieldThatsImmutableWithDefault"},
 | |
| 			Details: fmt.Sprintf("got: %v, want: %v", r.Spec.FieldThatsImmutableWithDefault,
 | |
| 				original.Spec.FieldThatsImmutableWithDefault),
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (r *Resource) CheckAllowedSubresourceUpdate(ctx context.Context, original *Resource) *apis.FieldError {
 | |
| 	if apis.GetUpdatedSubresource(ctx) == disallowedSubresource {
 | |
| 		return &apis.FieldError{
 | |
| 			Message: "Disallowed subresource update",
 | |
| 			Details: fmt.Sprintf("Disallowed subresource update: %s", disallowedSubresource),
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetListType implements apis.Listable
 | |
| func (r *Resource) GetListType() runtime.Object {
 | |
| 	return &ResourceList{}
 | |
| }
 | |
| 
 | |
| // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | |
| 
 | |
| // ResourceList is a list of Resource resources
 | |
| type ResourceList struct {
 | |
| 	metav1.TypeMeta `json:",inline"`
 | |
| 	metav1.ListMeta `json:"metadata"`
 | |
| 
 | |
| 	Items []Resource `json:"items"`
 | |
| }
 |