Skip to content

Commit 4812ea8

Browse files
authored
Merge pull request kubernetes#125570 from sanchezl/test-additional-types
KEP-4222: Cover aggregator and apiextension types in unstructured roundtrip test.
2 parents 762a85e + aaa7364 commit 4812ea8

File tree

10 files changed

+1440
-213
lines changed

10 files changed

+1440
-213
lines changed

pkg/api/testing/unstructured_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func TestRoundtripToUnstructured(t *testing.T) {
144144
}
145145
}
146146

147-
roundtrip.RoundtripToUnstructured(t, legacyscheme.Scheme, FuzzerFuncs, skipped)
147+
roundtrip.RoundtripToUnstructured(t, legacyscheme.Scheme, FuzzerFuncs, skipped, nil)
148148
}
149149

150150
func TestRoundTripWithEmptyCreationTimestamp(t *testing.T) {

staging/src/k8s.io/apiextensions-apiserver/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ godebug default=go1.23
88

99
require (
1010
github.com/emicklei/go-restful/v3 v3.11.0
11+
github.com/fxamacker/cbor/v2 v2.7.0
1112
github.com/gogo/protobuf v1.3.2
1213
github.com/google/cel-go v0.21.0
1314
github.com/google/gnostic-models v0.6.8
@@ -52,7 +53,6 @@ require (
5253
github.com/dustin/go-humanize v1.0.1 // indirect
5354
github.com/felixge/httpsnoop v1.0.4 // indirect
5455
github.com/fsnotify/fsnotify v1.7.0 // indirect
55-
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
5656
github.com/go-logr/logr v1.4.2 // indirect
5757
github.com/go-logr/stdr v1.2.2 // indirect
5858
github.com/go-openapi/jsonpointer v0.21.0 // indirect

staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1/marshal.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,42 @@ import (
2020
"bytes"
2121
"errors"
2222

23+
cbor "k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct"
2324
"k8s.io/apimachinery/pkg/util/json"
2425
)
2526

2627
var jsTrue = []byte("true")
2728
var jsFalse = []byte("false")
2829

30+
// The CBOR parsing related constants and functions below are not exported so they can be
31+
// easily removed at a future date when the CBOR library provides equivalent functionality.
32+
33+
type cborMajorType int
34+
35+
const (
36+
// https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1
37+
cborUnsignedInteger cborMajorType = 0
38+
cborNegativeInteger cborMajorType = 1
39+
cborByteString cborMajorType = 2
40+
cborTextString cborMajorType = 3
41+
cborArray cborMajorType = 4
42+
cborMap cborMajorType = 5
43+
cborTag cborMajorType = 6
44+
cborOther cborMajorType = 7
45+
)
46+
47+
const (
48+
// from https://www.rfc-editor.org/rfc/rfc8949.html#name-jump-table-for-initial-byte.
49+
// additionally, see https://www.rfc-editor.org/rfc/rfc8949.html#section-3.3-5.
50+
cborFalseValue = 0xf4
51+
cborTrueValue = 0xf5
52+
cborNullValue = 0xf6
53+
)
54+
55+
func cborType(b byte) cborMajorType {
56+
return cborMajorType(b >> 5)
57+
}
58+
2959
func (s JSONSchemaPropsOrBool) MarshalJSON() ([]byte, error) {
3060
if s.Schema != nil {
3161
return json.Marshal(s.Schema)
@@ -59,6 +89,39 @@ func (s *JSONSchemaPropsOrBool) UnmarshalJSON(data []byte) error {
5989
return nil
6090
}
6191

92+
func (s JSONSchemaPropsOrBool) MarshalCBOR() ([]byte, error) {
93+
if s.Schema != nil {
94+
return cbor.Marshal(s.Schema)
95+
}
96+
return cbor.Marshal(s.Allows)
97+
}
98+
99+
func (s *JSONSchemaPropsOrBool) UnmarshalCBOR(data []byte) error {
100+
switch {
101+
case len(data) == 0:
102+
// ideally we would avoid modifying *s here, but we are matching the behavior of UnmarshalJSON
103+
*s = JSONSchemaPropsOrBool{}
104+
return nil
105+
case cborType(data[0]) == cborMap:
106+
var p JSONSchemaProps
107+
if err := cbor.Unmarshal(data, &p); err != nil {
108+
return err
109+
}
110+
*s = JSONSchemaPropsOrBool{Allows: true, Schema: &p}
111+
return nil
112+
case data[0] == cborTrueValue:
113+
*s = JSONSchemaPropsOrBool{Allows: true}
114+
return nil
115+
case data[0] == cborFalseValue:
116+
*s = JSONSchemaPropsOrBool{Allows: false}
117+
return nil
118+
default:
119+
// ideally, this case would not also capture a null input value,
120+
// but we are matching the behavior of the UnmarshalJSON
121+
return errors.New("boolean or JSON schema expected")
122+
}
123+
}
124+
62125
func (s JSONSchemaPropsOrStringArray) MarshalJSON() ([]byte, error) {
63126
if len(s.Property) > 0 {
64127
return json.Marshal(s.Property)
@@ -91,6 +154,40 @@ func (s *JSONSchemaPropsOrStringArray) UnmarshalJSON(data []byte) error {
91154
return nil
92155
}
93156

157+
func (s JSONSchemaPropsOrStringArray) MarshalCBOR() ([]byte, error) {
158+
if len(s.Property) > 0 {
159+
return cbor.Marshal(s.Property)
160+
}
161+
if s.Schema != nil {
162+
return cbor.Marshal(s.Schema)
163+
}
164+
return cbor.Marshal(nil)
165+
}
166+
167+
func (s *JSONSchemaPropsOrStringArray) UnmarshalCBOR(data []byte) error {
168+
if len(data) > 0 && cborType(data[0]) == cborArray {
169+
var a []string
170+
if err := cbor.Unmarshal(data, &a); err != nil {
171+
return err
172+
}
173+
*s = JSONSchemaPropsOrStringArray{Property: a}
174+
return nil
175+
}
176+
if len(data) > 0 && cborType(data[0]) == cborMap {
177+
var p JSONSchemaProps
178+
if err := cbor.Unmarshal(data, &p); err != nil {
179+
return err
180+
}
181+
*s = JSONSchemaPropsOrStringArray{Schema: &p}
182+
return nil
183+
}
184+
// At this point we either have: empty data, a null value, or an
185+
// unexpected type. In order to match the behavior of the existing
186+
// UnmarshalJSON, no error is returned and *s is overwritten here.
187+
*s = JSONSchemaPropsOrStringArray{}
188+
return nil
189+
}
190+
94191
func (s JSONSchemaPropsOrArray) MarshalJSON() ([]byte, error) {
95192
if len(s.JSONSchemas) > 0 {
96193
return json.Marshal(s.JSONSchemas)
@@ -120,6 +217,37 @@ func (s *JSONSchemaPropsOrArray) UnmarshalJSON(data []byte) error {
120217
return nil
121218
}
122219

220+
func (s JSONSchemaPropsOrArray) MarshalCBOR() ([]byte, error) {
221+
if len(s.JSONSchemas) > 0 {
222+
return cbor.Marshal(s.JSONSchemas)
223+
}
224+
return cbor.Marshal(s.Schema)
225+
}
226+
227+
func (s *JSONSchemaPropsOrArray) UnmarshalCBOR(data []byte) error {
228+
if len(data) > 0 && cborType(data[0]) == cborMap {
229+
var p JSONSchemaProps
230+
if err := cbor.Unmarshal(data, &p); err != nil {
231+
return err
232+
}
233+
*s = JSONSchemaPropsOrArray{Schema: &p}
234+
return nil
235+
}
236+
if len(data) > 0 && cborType(data[0]) == cborArray {
237+
var a []JSONSchemaProps
238+
if err := cbor.Unmarshal(data, &a); err != nil {
239+
return err
240+
}
241+
*s = JSONSchemaPropsOrArray{JSONSchemas: a}
242+
return nil
243+
}
244+
// At this point we either have: empty data, a null value, or an
245+
// unexpected type. In order to match the behavior of the existing
246+
// UnmarshalJSON, no error is returned and *s is overwritten here.
247+
*s = JSONSchemaPropsOrArray{}
248+
return nil
249+
}
250+
123251
func (s JSON) MarshalJSON() ([]byte, error) {
124252
if len(s.Raw) > 0 {
125253
return s.Raw, nil
@@ -134,3 +262,34 @@ func (s *JSON) UnmarshalJSON(data []byte) error {
134262
}
135263
return nil
136264
}
265+
266+
func (s JSON) MarshalCBOR() ([]byte, error) {
267+
// Note that non-semantic whitespace is lost during the transcoding performed here.
268+
// We do not forsee this to be a problem given the current known uses of this type.
269+
// Other limitations that arise when roundtripping JSON via dynamic clients also apply
270+
// here, for example: insignificant whitespace handling, number handling, and map key ordering.
271+
if len(s.Raw) == 0 {
272+
return []byte{cborNullValue}, nil
273+
}
274+
var u any
275+
if err := json.Unmarshal(s.Raw, &u); err != nil {
276+
return nil, err
277+
}
278+
return cbor.Marshal(u)
279+
}
280+
281+
func (s *JSON) UnmarshalCBOR(data []byte) error {
282+
if len(data) == 0 || data[0] == cborNullValue {
283+
return nil
284+
}
285+
var u any
286+
if err := cbor.Unmarshal(data, &u); err != nil {
287+
return err
288+
}
289+
raw, err := json.Marshal(u)
290+
if err != nil {
291+
return err
292+
}
293+
s.Raw = raw
294+
return nil
295+
}

0 commit comments

Comments
 (0)