github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/testing/cacheable_object.go (about)

     1  /*
     2  Copyright 2019 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 testing
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"testing"
    24  
    25  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime"
    26  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    27  )
    28  
    29  // nonCacheableTestObject implements json.Marshaler and proto.Marshaler interfaces
    30  // for mocking purpose.
    31  // +k8s:deepcopy-gen=false
    32  type noncacheableTestObject struct {
    33  	gvk schema.GroupVersionKind
    34  }
    35  
    36  // MarshalJSON implements json.Marshaler interface.
    37  func (*noncacheableTestObject) MarshalJSON() ([]byte, error) {
    38  	return []byte("\"json-result\""), nil
    39  }
    40  
    41  // Marshal implements proto.Marshaler interface.
    42  func (*noncacheableTestObject) Marshal() ([]byte, error) {
    43  	return []byte("\"proto-result\""), nil
    44  }
    45  
    46  // DeepCopyObject implements runtime.Object interface.
    47  func (*noncacheableTestObject) DeepCopyObject() runtime.Object {
    48  	panic("DeepCopy unimplemented for noncacheableTestObject")
    49  }
    50  
    51  // GetObjectKind implements runtime.Object interface.
    52  func (o *noncacheableTestObject) GetObjectKind() schema.ObjectKind {
    53  	return o
    54  }
    55  
    56  // GroupVersionKind implements schema.ObjectKind interface.
    57  func (o *noncacheableTestObject) GroupVersionKind() schema.GroupVersionKind {
    58  	return o.gvk
    59  }
    60  
    61  // SetGroupVersionKind implements schema.ObjectKind interface.
    62  func (o *noncacheableTestObject) SetGroupVersionKind(gvk schema.GroupVersionKind) {
    63  	o.gvk = gvk
    64  }
    65  
    66  var _ runtime.CacheableObject = &MockCacheableObject{}
    67  
    68  // MochCacheableObject is used to test CacheableObject interface.
    69  // +k8s:deepcopy-gen=false
    70  type MockCacheableObject struct {
    71  	gvk schema.GroupVersionKind
    72  
    73  	t *testing.T
    74  
    75  	runEncode      bool
    76  	returnSelf     bool
    77  	expectedResult string
    78  	expectedError  error
    79  
    80  	intercepted []runtime.Identifier
    81  }
    82  
    83  // DeepCopyObject implements runtime.Object interface.
    84  func (m *MockCacheableObject) DeepCopyObject() runtime.Object {
    85  	panic("DeepCopy unimplemented for MockCacheableObject")
    86  }
    87  
    88  // GetObjectKind implements runtime.Object interface.
    89  func (m *MockCacheableObject) GetObjectKind() schema.ObjectKind {
    90  	return m
    91  }
    92  
    93  // GroupVersionKind implements schema.ObjectKind interface.
    94  func (m *MockCacheableObject) GroupVersionKind() schema.GroupVersionKind {
    95  	return m.gvk
    96  }
    97  
    98  // SetGroupVersionKind implements schema.ObjectKind interface.
    99  func (m *MockCacheableObject) SetGroupVersionKind(gvk schema.GroupVersionKind) {
   100  	m.gvk = gvk
   101  }
   102  
   103  // Marshal implements proto.Marshaler interface.
   104  // This is implemented to avoid errors from protobuf serializer.
   105  func (*MockCacheableObject) Marshal() ([]byte, error) {
   106  	return []byte("\"proto-result\""), nil
   107  }
   108  
   109  // CacheEncode implements runtime.CacheableObject interface.
   110  func (m *MockCacheableObject) CacheEncode(id runtime.Identifier, encode func(runtime.Object, io.Writer) error, w io.Writer) error {
   111  	m.intercepted = append(m.intercepted, id)
   112  	if m.runEncode {
   113  		return encode(m.GetObject(), w)
   114  	}
   115  	if _, err := w.Write([]byte(m.expectedResult)); err != nil {
   116  		m.t.Errorf("couldn't write to io.Writer: %v", err)
   117  	}
   118  	return m.expectedError
   119  }
   120  
   121  // GetObject implements runtime.CacheableObject interface.
   122  func (m *MockCacheableObject) GetObject() runtime.Object {
   123  	if m.returnSelf {
   124  		return m
   125  	}
   126  	gvk := schema.GroupVersionKind{Group: "group", Version: "version", Kind: "noncacheableTestObject"}
   127  	return &noncacheableTestObject{gvk: gvk}
   128  }
   129  
   130  func (m *MockCacheableObject) interceptedCalls() []runtime.Identifier {
   131  	return m.intercepted
   132  }
   133  
   134  type testBuffer struct {
   135  	writer io.Writer
   136  	t      *testing.T
   137  	object *MockCacheableObject
   138  }
   139  
   140  // Write implements io.Writer interface.
   141  func (b *testBuffer) Write(p []byte) (int, error) {
   142  	// Before writing any byte, check if <object> has already
   143  	// intercepted any CacheEncode operation.
   144  	if len(b.object.interceptedCalls()) == 0 {
   145  		b.t.Errorf("writing to buffer without handling MockCacheableObject")
   146  	}
   147  	return b.writer.Write(p)
   148  }
   149  
   150  // CacheableObjectTest implements a test that should be run for every
   151  // runtime.Encoder interface implementation.
   152  // It checks whether CacheableObject is properly supported by it.
   153  func CacheableObjectTest(t *testing.T, e runtime.Encoder) {
   154  	gvk1 := schema.GroupVersionKind{Group: "group", Version: "version1", Kind: "MockCacheableObject"}
   155  
   156  	testCases := []struct {
   157  		desc           string
   158  		runEncode      bool
   159  		returnSelf     bool
   160  		expectedResult string
   161  		expectedError  error
   162  	}{
   163  		{
   164  			desc:      "delegate",
   165  			runEncode: true,
   166  		},
   167  		{
   168  			desc:       "delegate return self",
   169  			runEncode:  true,
   170  			returnSelf: true,
   171  		},
   172  		{
   173  			desc:           "cached success",
   174  			runEncode:      false,
   175  			expectedResult: "result",
   176  			expectedError:  nil,
   177  		},
   178  		{
   179  			desc:           "cached failure",
   180  			runEncode:      false,
   181  			expectedResult: "",
   182  			expectedError:  fmt.Errorf("encoding error"),
   183  		},
   184  	}
   185  
   186  	for _, test := range testCases {
   187  		t.Run(test.desc, func(t *testing.T) {
   188  			obj := &MockCacheableObject{
   189  				gvk:            gvk1,
   190  				t:              t,
   191  				runEncode:      test.runEncode,
   192  				returnSelf:     test.returnSelf,
   193  				expectedResult: test.expectedResult,
   194  				expectedError:  test.expectedError,
   195  			}
   196  			buffer := bytes.NewBuffer(nil)
   197  			w := &testBuffer{
   198  				writer: buffer,
   199  				t:      t,
   200  				object: obj,
   201  			}
   202  
   203  			if err := e.Encode(obj, w); err != test.expectedError {
   204  				t.Errorf("unexpected error: %v, expected: %v", err, test.expectedError)
   205  			}
   206  			if !test.runEncode {
   207  				if result := buffer.String(); result != test.expectedResult {
   208  					t.Errorf("unexpected result: %s, expected: %s", result, test.expectedResult)
   209  				}
   210  			}
   211  			intercepted := obj.interceptedCalls()
   212  			if len(intercepted) != 1 {
   213  				t.Fatalf("unexpected number of intercepted calls: %v", intercepted)
   214  			}
   215  			if intercepted[0] != e.Identifier() {
   216  				t.Errorf("unexpected intercepted call: %v, expected: %v", intercepted, e.Identifier())
   217  			}
   218  		})
   219  	}
   220  }