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 }