github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/serializer/versioning/versioning_test.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package versioning
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"io/ioutil"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime"
    27  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    28  	runtimetesting "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/testing"
    29  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/diff"
    30  )
    31  
    32  type testDecodable struct {
    33  	Other string
    34  	Value int `json:"value"`
    35  	gvk   schema.GroupVersionKind
    36  }
    37  
    38  func (d *testDecodable) GetObjectKind() schema.ObjectKind                { return d }
    39  func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
    40  func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind       { return d.gvk }
    41  func (d *testDecodable) DeepCopyObject() runtime.Object {
    42  	// no real deepcopy because these tests check for pointer equality
    43  	return d
    44  }
    45  
    46  type testNestedDecodable struct {
    47  	Other string
    48  	Value int `json:"value"`
    49  
    50  	gvk          schema.GroupVersionKind
    51  	nestedCalled bool
    52  	nestedErr    error
    53  }
    54  
    55  func (d *testNestedDecodable) GetObjectKind() schema.ObjectKind                { return d }
    56  func (d *testNestedDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
    57  func (d *testNestedDecodable) GroupVersionKind() schema.GroupVersionKind       { return d.gvk }
    58  func (d *testNestedDecodable) DeepCopyObject() runtime.Object {
    59  	// no real deepcopy because these tests check for pointer equality
    60  	return d
    61  }
    62  
    63  func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error {
    64  	d.nestedCalled = true
    65  	return d.nestedErr
    66  }
    67  
    68  func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
    69  	d.nestedCalled = true
    70  	return d.nestedErr
    71  }
    72  
    73  func TestNestedDecode(t *testing.T) {
    74  	n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
    75  	decoder := &mockSerializer{obj: n}
    76  	codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil, "TestNestedDecode")
    77  	if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr {
    78  		t.Errorf("unexpected error: %v", err)
    79  	}
    80  	if !n.nestedCalled {
    81  		t.Errorf("did not invoke nested decoder")
    82  	}
    83  }
    84  
    85  func TestNestedDecodeStrictDecodingError(t *testing.T) {
    86  	strictErr := runtime.NewStrictDecodingError([]error{fmt.Errorf("duplicate field")})
    87  	n := &testNestedDecodable{nestedErr: strictErr}
    88  	decoder := &mockSerializer{obj: n}
    89  	codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil, "TestNestedDecode")
    90  	o, _, err := codec.Decode([]byte(`{}`), nil, n)
    91  	if strictErr, ok := runtime.AsStrictDecodingError(err); !ok || err != strictErr {
    92  		t.Errorf("unexpected error: %v", err)
    93  	}
    94  	if o != n {
    95  		t.Errorf("did not successfully decode with strict decoding error: %v", o)
    96  	}
    97  	if !n.nestedCalled {
    98  		t.Errorf("did not invoke nested decoder")
    99  	}
   100  }
   101  
   102  func TestNestedEncode(t *testing.T) {
   103  	n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
   104  	n2 := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode 2")}
   105  	encoder := &mockSerializer{obj: n}
   106  	codec := NewCodec(
   107  		encoder, nil,
   108  		&checkConvertor{obj: n2, groupVersion: schema.GroupVersion{Group: "other"}},
   109  		nil,
   110  		&mockTyper{gvks: []schema.GroupVersionKind{{Kind: "test"}}},
   111  		nil,
   112  		schema.GroupVersion{Group: "other"}, nil,
   113  		"TestNestedEncode",
   114  	)
   115  	if err := codec.Encode(n, ioutil.Discard); err != n2.nestedErr {
   116  		t.Errorf("unexpected error: %v", err)
   117  	}
   118  	if n.nestedCalled || !n2.nestedCalled {
   119  		t.Errorf("did not invoke correct nested decoder")
   120  	}
   121  }
   122  
   123  func TestNestedEncodeError(t *testing.T) {
   124  	n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to encode")}
   125  	gvk1 := schema.GroupVersionKind{Kind: "test", Group: "other", Version: "v1"}
   126  	gvk2 := schema.GroupVersionKind{Kind: "test", Group: "other", Version: "v2"}
   127  	n.SetGroupVersionKind(gvk1)
   128  	encoder := &mockSerializer{obj: n}
   129  	codec := NewCodec(
   130  		encoder, nil,
   131  		&mockConvertor{},
   132  		nil,
   133  		&mockTyper{gvks: []schema.GroupVersionKind{gvk1, gvk2}},
   134  		nil,
   135  		schema.GroupVersion{Group: "other", Version: "v2"}, nil,
   136  		"TestNestedEncodeError",
   137  	)
   138  	if err := codec.Encode(n, ioutil.Discard); err != n.nestedErr {
   139  		t.Errorf("unexpected error: %v", err)
   140  	}
   141  	if n.GroupVersionKind() != gvk1 {
   142  		t.Errorf("unexpected gvk of input object: %v", n.GroupVersionKind())
   143  	}
   144  }
   145  
   146  func TestDecode(t *testing.T) {
   147  	gvk1 := &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
   148  	decodable1 := &testDecodable{}
   149  	decodable2 := &testDecodable{}
   150  	decodable3 := &testDecodable{}
   151  
   152  	testCases := []struct {
   153  		serializer runtime.Serializer
   154  		convertor  runtime.ObjectConvertor
   155  		creater    runtime.ObjectCreater
   156  		typer      runtime.ObjectTyper
   157  		defaulter  runtime.ObjectDefaulter
   158  		yaml       bool
   159  		pretty     bool
   160  
   161  		encodes, decodes runtime.GroupVersioner
   162  
   163  		defaultGVK *schema.GroupVersionKind
   164  		into       runtime.Object
   165  
   166  		errFn          func(error) bool
   167  		expectedObject runtime.Object
   168  		sameObject     runtime.Object
   169  		expectedGVK    *schema.GroupVersionKind
   170  	}{
   171  		{
   172  			serializer:  &mockSerializer{actual: gvk1},
   173  			convertor:   &checkConvertor{groupVersion: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}},
   174  			expectedGVK: gvk1,
   175  			decodes:     schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal},
   176  		},
   177  		{
   178  			serializer:  &mockSerializer{actual: gvk1, obj: decodable1},
   179  			convertor:   &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}},
   180  			expectedGVK: gvk1,
   181  			sameObject:  decodable2,
   182  			decodes:     schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal},
   183  		},
   184  		// defaultGVK.Group is allowed to force a conversion to the destination group
   185  		{
   186  			serializer:  &mockSerializer{actual: gvk1, obj: decodable1},
   187  			defaultGVK:  &schema.GroupVersionKind{Group: "force"},
   188  			convertor:   &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "force", Version: runtime.APIVersionInternal}},
   189  			expectedGVK: gvk1,
   190  			sameObject:  decodable2,
   191  			decodes:     schema.GroupVersion{Group: "force", Version: runtime.APIVersionInternal},
   192  		},
   193  		// uses direct conversion for into when objects differ
   194  		{
   195  			into:        decodable3,
   196  			serializer:  &mockSerializer{actual: gvk1, obj: decodable1},
   197  			convertor:   &checkConvertor{in: decodable1, obj: decodable3, directConvert: true},
   198  			expectedGVK: gvk1,
   199  			sameObject:  decodable3,
   200  		},
   201  		// decode into the same version as the serialized object
   202  		{
   203  			decodes: schema.GroupVersions{gvk1.GroupVersion()},
   204  
   205  			serializer:     &mockSerializer{actual: gvk1, obj: decodable1},
   206  			convertor:      &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}},
   207  			expectedGVK:    gvk1,
   208  			expectedObject: decodable1,
   209  		},
   210  	}
   211  
   212  	for i, test := range testCases {
   213  		t.Logf("%d", i)
   214  		s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.typer, test.defaulter, test.encodes, test.decodes, fmt.Sprintf("mock-%d", i))
   215  		obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into)
   216  
   217  		if !reflect.DeepEqual(test.expectedGVK, gvk) {
   218  			t.Errorf("%d: unexpected GVK: %v", i, gvk)
   219  		}
   220  
   221  		switch {
   222  		case err == nil && test.errFn != nil:
   223  			t.Errorf("%d: failed: %v", i, err)
   224  			continue
   225  		case err != nil && test.errFn == nil:
   226  			t.Errorf("%d: failed: %v", i, err)
   227  			continue
   228  		case err != nil:
   229  			if !test.errFn(err) {
   230  				t.Errorf("%d: failed: %v", i, err)
   231  			}
   232  			if obj != nil {
   233  				t.Errorf("%d: should have returned nil object", i)
   234  			}
   235  			continue
   236  		}
   237  
   238  		if test.into != nil && test.into != obj {
   239  			t.Errorf("%d: expected into to be returned: %v", i, obj)
   240  			continue
   241  		}
   242  
   243  		switch {
   244  		case test.expectedObject != nil:
   245  			if !reflect.DeepEqual(test.expectedObject, obj) {
   246  				t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
   247  			}
   248  		case test.sameObject != nil:
   249  			if test.sameObject != obj {
   250  				t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.sameObject, obj))
   251  			}
   252  		case obj != nil:
   253  			t.Errorf("%d: unexpected object: %#v", i, obj)
   254  		}
   255  	}
   256  }
   257  
   258  type checkConvertor struct {
   259  	err           error
   260  	in, obj       runtime.Object
   261  	groupVersion  runtime.GroupVersioner
   262  	directConvert bool
   263  }
   264  
   265  func (c *checkConvertor) Convert(in, out, context interface{}) error {
   266  	if !c.directConvert {
   267  		return fmt.Errorf("unexpected call to Convert")
   268  	}
   269  	if c.in != nil && c.in != in {
   270  		return fmt.Errorf("unexpected in: %s", in)
   271  	}
   272  	if c.obj != nil && c.obj != out {
   273  		return fmt.Errorf("unexpected out: %s", out)
   274  	}
   275  	return c.err
   276  }
   277  func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) {
   278  	if c.directConvert {
   279  		return nil, fmt.Errorf("unexpected call to ConvertToVersion")
   280  	}
   281  	if c.in != nil && c.in != in {
   282  		return nil, fmt.Errorf("unexpected in: %s", in)
   283  	}
   284  	if !reflect.DeepEqual(c.groupVersion, outVersion) {
   285  		return nil, fmt.Errorf("unexpected outversion: %s (%s)", outVersion, c.groupVersion)
   286  	}
   287  	return c.obj, c.err
   288  }
   289  func (c *checkConvertor) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
   290  	return "", "", fmt.Errorf("unexpected call to ConvertFieldLabel")
   291  }
   292  
   293  type mockConvertor struct {
   294  }
   295  
   296  func (c *mockConvertor) Convert(in, out, context interface{}) error {
   297  	return fmt.Errorf("unexpect call to Convert")
   298  }
   299  
   300  func (c *mockConvertor) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) {
   301  	objectKind := in.GetObjectKind()
   302  	inGVK := objectKind.GroupVersionKind()
   303  	if out, ok := outVersion.KindForGroupVersionKinds([]schema.GroupVersionKind{inGVK}); ok {
   304  		objectKind.SetGroupVersionKind(out)
   305  	} else {
   306  		return nil, fmt.Errorf("unexpected conversion")
   307  	}
   308  	return in, nil
   309  }
   310  
   311  func (c *mockConvertor) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
   312  	return "", "", fmt.Errorf("unexpected call to ConvertFieldLabel")
   313  }
   314  
   315  type mockSerializer struct {
   316  	err            error
   317  	obj            runtime.Object
   318  	encodingObjGVK schema.GroupVersionKind
   319  
   320  	defaults, actual *schema.GroupVersionKind
   321  	into             runtime.Object
   322  }
   323  
   324  func (s *mockSerializer) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
   325  	s.defaults = defaults
   326  	s.into = into
   327  	return s.obj, s.actual, s.err
   328  }
   329  
   330  func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error {
   331  	s.obj = obj
   332  	s.encodingObjGVK = obj.GetObjectKind().GroupVersionKind()
   333  	return s.err
   334  }
   335  
   336  func (s *mockSerializer) Identifier() runtime.Identifier {
   337  	return runtime.Identifier("mock")
   338  }
   339  
   340  type mockTyper struct {
   341  	gvks        []schema.GroupVersionKind
   342  	unversioned bool
   343  	err         error
   344  }
   345  
   346  func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
   347  	return t.gvks, t.unversioned, t.err
   348  }
   349  
   350  func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool {
   351  	return true
   352  }
   353  
   354  func TestDirectCodecEncode(t *testing.T) {
   355  	serializer := mockSerializer{}
   356  	typer := mockTyper{
   357  		gvks: []schema.GroupVersionKind{
   358  			{
   359  				Group: "wrong_group",
   360  				Kind:  "some_kind",
   361  			},
   362  			{
   363  				Group: "expected_group",
   364  				Kind:  "some_kind",
   365  			},
   366  		},
   367  	}
   368  
   369  	c := runtime.WithVersionEncoder{
   370  		Version:     schema.GroupVersion{Group: "expected_group"},
   371  		Encoder:     &serializer,
   372  		ObjectTyper: &typer,
   373  	}
   374  	c.Encode(&testDecodable{}, ioutil.Discard)
   375  	if e, a := "expected_group", serializer.encodingObjGVK.Group; e != a {
   376  		t.Errorf("expected group to be %v, got %v", e, a)
   377  	}
   378  }
   379  
   380  func TestCacheableObject(t *testing.T) {
   381  	gvk1 := schema.GroupVersionKind{Group: "group", Version: "version1", Kind: "MockCacheableObject"}
   382  	gvk2 := schema.GroupVersionKind{Group: "group", Version: "version2", Kind: "MockCacheableObject"}
   383  
   384  	encoder := NewCodec(
   385  		&mockSerializer{}, &mockSerializer{},
   386  		&mockConvertor{}, nil,
   387  		&mockTyper{gvks: []schema.GroupVersionKind{gvk1, gvk2}}, nil,
   388  		gvk1.GroupVersion(), gvk2.GroupVersion(),
   389  		"TestCacheableObject")
   390  
   391  	runtimetesting.CacheableObjectTest(t, encoder)
   392  }
   393  
   394  func BenchmarkIdentifier(b *testing.B) {
   395  	encoder := &mockSerializer{}
   396  	gv := schema.GroupVersion{Group: "group", Version: "version"}
   397  
   398  	for i := 0; i < b.N; i++ {
   399  		id := identifier(gv, encoder)
   400  		// Avoid optimizing by compiler.
   401  		if id[0] != '{' {
   402  			b.Errorf("unexpected identifier: %s", id)
   403  		}
   404  	}
   405  }