mirror of https://github.com/knative/pkg.git
				
				
				
			
		
			
				
	
	
		
			515 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			515 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
Copyright 2019 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 apis_test
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"knative.dev/pkg/apis"
 | 
						|
	"knative.dev/pkg/ptr"
 | 
						|
	. "knative.dev/pkg/testing"
 | 
						|
)
 | 
						|
 | 
						|
func TestCheckDeprecated(t *testing.T) {
 | 
						|
 | 
						|
	testCases := map[string]struct {
 | 
						|
		strict   bool
 | 
						|
		obj      interface{}
 | 
						|
		wantErrs []string
 | 
						|
	}{
 | 
						|
		"create strict, string": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "an error",
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"string",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, stringptr": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStringPtr: ptr.String("test string"),
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"stringPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, int": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedInt: 42,
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"int",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, intptr": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedIntPtr: ptr.Int64(42),
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"intPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, map": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedMap: map[string]string{"hello": "failure"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"map",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, slice": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedSlice: []string{"hello", "failure"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"slice",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, struct": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStruct: InnerDefaultStruct{FieldAsString: "not ok"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"struct",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, structptr": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"structPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, not json": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedNotJSON: "fail",
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"DeprecatedNotJSON",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, inlined": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				InlinedStruct: InlinedStruct{
 | 
						|
					DeprecatedField: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"fieldA",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, inlined ptr": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
					DeprecatedField: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"fieldB",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, inlined nested": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				InlinedStruct: InlinedStruct{
 | 
						|
					InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
						DeprecatedField: "fail",
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"fieldB",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"create strict, all errors": {
 | 
						|
			strict: true,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString:    "an error",
 | 
						|
				DeprecatedStringPtr: ptr.String("test string"),
 | 
						|
				DeprecatedInt:       42,
 | 
						|
				DeprecatedIntPtr:    ptr.Int64(42),
 | 
						|
				DeprecatedMap:       map[string]string{"hello": "failure"},
 | 
						|
				DeprecatedSlice:     []string{"hello", "failure"},
 | 
						|
				DeprecatedStruct:    InnerDefaultStruct{FieldAsString: "not ok"},
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
				InlinedStruct: InlinedStruct{
 | 
						|
					DeprecatedField: "fail",
 | 
						|
					InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
						DeprecatedField: "fail",
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"string",
 | 
						|
				"stringPtr",
 | 
						|
				"int",
 | 
						|
				"intPtr",
 | 
						|
				"map",
 | 
						|
				"slice",
 | 
						|
				"struct",
 | 
						|
				"structPtr",
 | 
						|
				"fieldA",
 | 
						|
				"fieldB",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for n, tc := range testCases {
 | 
						|
		t.Run(n, func(t *testing.T) {
 | 
						|
			ctx := context.Background()
 | 
						|
			if tc.strict {
 | 
						|
				ctx = apis.DisallowDeprecated(ctx)
 | 
						|
			}
 | 
						|
			resp := apis.CheckDeprecated(ctx, tc.obj)
 | 
						|
 | 
						|
			if len(tc.wantErrs) > 0 {
 | 
						|
				for _, err := range tc.wantErrs {
 | 
						|
					var gotErr string
 | 
						|
					if resp != nil {
 | 
						|
						gotErr = resp.Error()
 | 
						|
					}
 | 
						|
					if !strings.Contains(gotErr, err) {
 | 
						|
						t.Errorf("Expected failure containing %q got %q", err, gotErr)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else if resp != nil {
 | 
						|
				t.Errorf("Expected no error, got %q", resp.Error())
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// This test makes sure that errors will flatten the duped error for fieldB.
 | 
						|
// It comes in on obj.InlinedStruct.InlinedPtrStruct.DeprecatedField and
 | 
						|
// obj.InlinedPtrStruct.DeprecatedField.
 | 
						|
func TestCheckDeprecated_Dedupe(t *testing.T) {
 | 
						|
 | 
						|
	obj := &InnerDefaultSubSpec{
 | 
						|
		InlinedStruct: InlinedStruct{
 | 
						|
			DeprecatedField: "fail",
 | 
						|
			InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
				DeprecatedField: "fail",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
			DeprecatedField: "fail",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	wantErr := "must not set the field(s): fieldA, fieldB"
 | 
						|
 | 
						|
	ctx := apis.DisallowDeprecated(context.Background())
 | 
						|
	resp := apis.CheckDeprecated(ctx, obj)
 | 
						|
 | 
						|
	gotErr := resp.Error()
 | 
						|
	if gotErr != wantErr {
 | 
						|
		t.Errorf("Expected failure %q got %q", wantErr, gotErr)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestCheckDeprecatedUpdate(t *testing.T) {
 | 
						|
 | 
						|
	testCases := map[string]struct {
 | 
						|
		strict   bool
 | 
						|
		obj      interface{}
 | 
						|
		org      interface{}
 | 
						|
		wantErrs []string
 | 
						|
	}{
 | 
						|
		"update strict, intptr": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedIntPtr: ptr.Int64(42),
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"intPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update strict, map": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedMap: map[string]string{"hello": "failure"},
 | 
						|
			},
 | 
						|
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"map",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update strict, slice": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedSlice: []string{"hello", "failure"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"slice",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update strict, struct": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStruct: InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"struct",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update strict, structptr": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not set",
 | 
						|
				"structPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update strict, all errors": {
 | 
						|
			strict: true,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString:    "an error",
 | 
						|
				DeprecatedStringPtr: ptr.String("test string"),
 | 
						|
				DeprecatedInt:       42,
 | 
						|
				DeprecatedIntPtr:    ptr.Int64(42),
 | 
						|
				DeprecatedMap:       map[string]string{"hello": "failure"},
 | 
						|
				DeprecatedSlice:     []string{"hello", "failure"},
 | 
						|
				DeprecatedStruct:    InnerDefaultStruct{FieldAsString: "not ok"},
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
				InlinedStruct: InlinedStruct{
 | 
						|
					DeprecatedField: "fail",
 | 
						|
					InlinedPtrStruct: &InlinedPtrStruct{
 | 
						|
						DeprecatedField: "fail",
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"string",
 | 
						|
				"stringPtr",
 | 
						|
				"int",
 | 
						|
				"intPtr",
 | 
						|
				"map",
 | 
						|
				"slice",
 | 
						|
				"struct",
 | 
						|
				"structPtr",
 | 
						|
				"fieldA",
 | 
						|
				"fieldB",
 | 
						|
			},
 | 
						|
		},
 | 
						|
 | 
						|
		"overwrite strict, string": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "original setting.",
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "fail setting.",
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"string",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, stringptr": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStringPtr: ptr.String("original string"),
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStringPtr: ptr.String("fail string"),
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"stringPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, int": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedInt: 10,
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedInt: 42,
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"int",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, intptr": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedIntPtr: ptr.Int64(10),
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedIntPtr: ptr.Int64(42),
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"intPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, map": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedMap: map[string]string{"goodbye": "existing"},
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedMap: map[string]string{"hello": "failure"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"map",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, slice": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedSlice: []string{"hello", "existing"},
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedSlice: []string{"hello", "failure"},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"slice",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, struct": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStruct: InnerDefaultStruct{
 | 
						|
					FieldAsString: "original",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStruct: InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"struct",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite strict, structptr": {
 | 
						|
			strict: true,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "original",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedStructPtr: &InnerDefaultStruct{
 | 
						|
					FieldAsString: "fail",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			wantErrs: []string{
 | 
						|
				"must not update",
 | 
						|
				"structPtr",
 | 
						|
			},
 | 
						|
		},
 | 
						|
 | 
						|
		"create, not strict": {
 | 
						|
			strict: false,
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "fail setting.",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"update, not strict": {
 | 
						|
			strict: false,
 | 
						|
			org:    &InnerDefaultSubSpec{},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "it's k",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		"overwrite, not strict": {
 | 
						|
			strict: false,
 | 
						|
			org: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "org",
 | 
						|
			},
 | 
						|
			obj: &InnerDefaultSubSpec{
 | 
						|
				DeprecatedString: "it's k",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for n, tc := range testCases {
 | 
						|
		t.Run(n, func(t *testing.T) {
 | 
						|
			ctx := context.Background()
 | 
						|
			if tc.strict {
 | 
						|
				ctx = apis.DisallowDeprecated(ctx)
 | 
						|
			}
 | 
						|
			resp := apis.CheckDeprecatedUpdate(ctx, tc.obj, tc.org)
 | 
						|
 | 
						|
			if len(tc.wantErrs) > 0 {
 | 
						|
				for _, err := range tc.wantErrs {
 | 
						|
					var gotErr string
 | 
						|
					if resp != nil {
 | 
						|
						gotErr = resp.Error()
 | 
						|
					}
 | 
						|
					if !strings.Contains(gotErr, err) {
 | 
						|
						t.Errorf("Expected failure containing %q got %q", err, gotErr)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else if resp != nil {
 | 
						|
				t.Errorf("Expected no error, got %q", resp.Error())
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |