mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 20:00:07 +00:00
Merge pull request #139964 from liggitt/cri-api-env-json
[master] Restore string JSON encoding of cri-api KeyValue (cherry picked from commit e62c2b04709d77f028b2d2dd3b57be567b4e7a60) Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
committed by
Brad Davidson
parent
ddf6b10b18
commit
60bea2b6e2
47
staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go
Normal file
47
staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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 v1
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// MarshalJSON() preserves pre-1.34 JSON encoding of value as a string (not base64),
|
||||
// stomping non-utf-8 data with the utf8 replacement character.
|
||||
func (k *KeyValue) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(stringKeyValue{
|
||||
Key: k.GetKey(),
|
||||
Value: string(k.GetValue()),
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON preserves pre-1.34 JSON decoding of value as a string (not base64),
|
||||
// stomping non-utf-8 data with the utf8 replacement character.
|
||||
func (k *KeyValue) UnmarshalJSON(data []byte) error {
|
||||
v := stringKeyValue{}
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
k.Key = v.Key
|
||||
k.Value = []byte(v.Value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// stringKeyValue matches the structure used to json-encode pre-1.34.
|
||||
// Non-UTF-8 characters in Value are coerced to the replacement character on encode/decode.
|
||||
type stringKeyValue struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
115
staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go
Normal file
115
staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api_json_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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 v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKeyValueCompat(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
envs []*KeyValue
|
||||
variantJSON string
|
||||
expectedJSON string
|
||||
expectedRoundTripped []*KeyValue
|
||||
}{
|
||||
{
|
||||
name: "null",
|
||||
envs: nil,
|
||||
expectedJSON: `null`,
|
||||
expectedRoundTripped: nil,
|
||||
},
|
||||
{
|
||||
name: "zero-length list",
|
||||
envs: []*KeyValue{},
|
||||
expectedJSON: `[]`,
|
||||
expectedRoundTripped: []*KeyValue{},
|
||||
},
|
||||
{
|
||||
name: "zero-value env",
|
||||
envs: []*KeyValue{{}},
|
||||
expectedJSON: `[{}]`,
|
||||
expectedRoundTripped: []*KeyValue{{}},
|
||||
},
|
||||
{
|
||||
name: "ascii env",
|
||||
envs: []*KeyValue{{Key: "key", Value: []byte("value")}},
|
||||
expectedJSON: `[{"key":"key","value":"value"}]`,
|
||||
expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("value")}},
|
||||
},
|
||||
{
|
||||
name: "utf8 env",
|
||||
envs: []*KeyValue{{Key: "key", Value: []byte("Iñtërnâtiônàlizætiøn🐹")}},
|
||||
expectedJSON: `[{"key":"key","value":"Iñtërnâtiônàlizætiøn🐹"}]`,
|
||||
expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("Iñtërnâtiônàlizætiøn🐹")}},
|
||||
},
|
||||
{
|
||||
name: "non-utf8 env",
|
||||
envs: []*KeyValue{{Key: "key", Value: []byte{'A', 0x80, 'Z'}}}, // invalid utf8 continuation byte (0x80)
|
||||
variantJSON: `[{"key":"key","value":"A` + "\x80" + `Z"}]`, // an alternate JSON input containing the invalid utf8 byte that should coerce to the same result
|
||||
expectedJSON: `[{"key":"key","value":"A\ufffdZ"}]`, // coerced to utf8 replacement character (\ufffd) on marshal
|
||||
expectedRoundTripped: []*KeyValue{{Key: "key", Value: []byte("A\ufffdZ")}}, // round-trips to replacement character (\ufffd) on unmarshal
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data, err := json.Marshal(tc.envs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(data) != tc.expectedJSON {
|
||||
t.Fatalf("json differed:\nwant: %s\ngot: %s", tc.expectedJSON, string(data))
|
||||
}
|
||||
|
||||
verifyJSON(t, data, tc.expectedRoundTripped)
|
||||
if len(tc.variantJSON) > 0 {
|
||||
verifyJSON(t, []byte(tc.variantJSON), tc.expectedRoundTripped)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func verifyJSON(t *testing.T, data []byte, expectedRoundTripped []*KeyValue) {
|
||||
t.Helper()
|
||||
|
||||
var rt []*KeyValue
|
||||
if err := json.Unmarshal(data, &rt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if (rt == nil) != (expectedRoundTripped == nil) {
|
||||
t.Fatalf("expected value (%#v) does not match actual round-tripped value (%#v) for nil", expectedRoundTripped, rt)
|
||||
}
|
||||
if rt == nil {
|
||||
return
|
||||
}
|
||||
if len(rt) != len(expectedRoundTripped) {
|
||||
t.Fatalf("length of expected value (%#v) does not match length of actual round-tripped value (%#v)", expectedRoundTripped, rt)
|
||||
}
|
||||
for i := range expectedRoundTripped {
|
||||
if want, got := expectedRoundTripped[i].Key, rt[i].Key; want != got {
|
||||
t.Fatalf("item[%d].key does not match: %s vs %s", i, want, got)
|
||||
}
|
||||
if want, got := expectedRoundTripped[i].Value, rt[i].Value; !bytes.Equal(want, got) {
|
||||
t.Fatalf("item[%d].value does not match: %v vs %v", i, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user