API server should offer metav1 Table/Partial transforms

Now that internal types are equivalent, allow the apiserver to serve
metav1 and metav1beta1 depending on the client. Test that in the
apiserver integration test and ensure we get the appropriate responses.

Register the metav1 type in the appropriate external locations.
This commit is contained in:
Clayton Coleman
2019-05-04 16:55:49 -04:00
parent e256c15df3
commit 33a3e325f7
10 changed files with 594 additions and 111 deletions

View File

@@ -548,7 +548,7 @@ func TestAPICRDProtobuf(t *testing.T) {
}
}
func TestTransformOnWatch(t *testing.T) {
func TestTransform(t *testing.T) {
tearDown, config, _, err := fixtures.StartDefaultServer(t)
if err != nil {
t.Fatal(err)
@@ -592,23 +592,23 @@ func TestTransformOnWatch(t *testing.T) {
testcases := []struct {
name string
accept string
includeObject metav1beta1.IncludeObjectPolicy
includeObject metav1.IncludeObjectPolicy
object func(*testing.T) (metav1.Object, string, string)
wantErr func(*testing.T, error)
wantBody func(*testing.T, io.Reader)
}{
{
name: "verify columns on cluster scoped resources",
name: "v1beta1 verify columns on cluster scoped resources",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "default", Namespace: ""}, "", "namespaces"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableWatchEvents(t, 1, 3, metav1beta1.IncludeMetadata, json.NewDecoder(w))
expectTableWatchEvents(t, 1, 3, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "verify columns on CRDs in json",
name: "v1beta1 verify columns on CRDs in json",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-1"}}}, metav1.CreateOptions{})
@@ -621,11 +621,11 @@ func TestTransformOnWatch(t *testing.T) {
return cr, crdGVR.Group, "foos"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableWatchEvents(t, 2, 2, metav1beta1.IncludeMetadata, json.NewDecoder(w))
expectTableWatchEvents(t, 2, 2, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "verify columns on CRDs in json;stream=watch",
name: "v1beta1 verify columns on CRDs in json;stream=watch",
accept: "application/json;stream=watch;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-2"}}}, metav1.CreateOptions{})
@@ -638,11 +638,11 @@ func TestTransformOnWatch(t *testing.T) {
return cr, crdGVR.Group, "foos"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableWatchEvents(t, 2, 2, metav1beta1.IncludeMetadata, json.NewDecoder(w))
expectTableWatchEvents(t, 2, 2, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "verify columns on CRDs in yaml",
name: "v1beta1 verify columns on CRDs in yaml",
accept: "application/yaml;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-3"}}}, metav1.CreateOptions{})
@@ -665,7 +665,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify columns on services",
name: "v1beta1 verify columns on services",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
@@ -679,13 +679,13 @@ func TestTransformOnWatch(t *testing.T) {
return svc, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableWatchEvents(t, 2, 7, metav1beta1.IncludeMetadata, json.NewDecoder(w))
expectTableWatchEvents(t, 2, 7, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "verify columns on services with no object",
name: "v1beta1 verify columns on services with no object",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
includeObject: metav1beta1.IncludeNone,
includeObject: metav1.IncludeNone,
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().Services(ns).Create(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "test-2"}, Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1000}}}})
@@ -698,13 +698,13 @@ func TestTransformOnWatch(t *testing.T) {
return obj, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableWatchEvents(t, 2, 7, metav1beta1.IncludeNone, json.NewDecoder(w))
expectTableWatchEvents(t, 2, 7, metav1.IncludeNone, json.NewDecoder(w))
},
},
{
name: "verify columns on services with full object",
name: "v1beta1 verify columns on services with full object",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
includeObject: metav1beta1.IncludeObject,
includeObject: metav1.IncludeObject,
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().Services(ns).Create(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "test-3"}, Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1000}}}})
@@ -717,7 +717,7 @@ func TestTransformOnWatch(t *testing.T) {
return obj, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
objects := expectTableWatchEvents(t, 2, 7, metav1beta1.IncludeObject, json.NewDecoder(w))
objects := expectTableWatchEvents(t, 2, 7, metav1.IncludeObject, json.NewDecoder(w))
var svc v1.Service
if err := json.Unmarshal(objects[1], &svc); err != nil {
t.Fatal(err)
@@ -728,7 +728,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify partial metadata object on config maps",
name: "v1beta1 verify partial metadata object on config maps",
accept: "application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
@@ -746,7 +746,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify partial metadata object on config maps in protobuf",
name: "v1beta1 verify partial metadata object on config maps in protobuf",
accept: "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
@@ -764,7 +764,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify error on unsupported mimetype protobuf for table conversion",
name: "v1beta1 verify error on unsupported mimetype protobuf for table conversion",
accept: "application/vnd.kubernetes.protobuf;as=Table;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
@@ -781,7 +781,7 @@ func TestTransformOnWatch(t *testing.T) {
},
{
name: "verify error on invalid mimetype - bad version",
accept: "application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1",
accept: "application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1alpha1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
@@ -792,7 +792,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify error on invalid mimetype - bad group",
name: "v1beta1 verify error on invalid mimetype - bad group",
accept: "application/json;as=PartialObjectMetadata;g=k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
@@ -804,7 +804,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify error on invalid mimetype - bad kind",
name: "v1beta1 verify error on invalid mimetype - bad kind",
accept: "application/json;as=PartialObject;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
@@ -816,7 +816,7 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify error on invalid mimetype - missing kind",
name: "v1beta1 verify error on invalid mimetype - missing kind",
accept: "application/json;g=meta.k8s.io;v=v1beta1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
@@ -828,9 +828,241 @@ func TestTransformOnWatch(t *testing.T) {
},
},
{
name: "verify error on invalid transform parameter",
name: "v1beta1 verify error on invalid transform parameter",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1beta1",
includeObject: metav1beta1.IncludeObjectPolicy("unrecognized"),
includeObject: metav1.IncludeObjectPolicy("unrecognized"),
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsBadRequest(err) || !strings.Contains(err.Error(), `Invalid value: "unrecognized": must be 'Metadata', 'Object', 'None', or empty`) {
t.Fatal(err)
}
},
},
{
name: "v1 verify columns on cluster scoped resources",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "default", Namespace: ""}, "", "namespaces"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableV1WatchEvents(t, 1, 3, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "v1 verify columns on CRDs in json",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-4"}}}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("unable to create cr: %v", err)
}
if _, err := crclient.Patch("test-4", types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`), metav1.PatchOptions{}); err != nil {
t.Fatalf("unable to patch cr: %v", err)
}
return cr, crdGVR.Group, "foos"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableV1WatchEvents(t, 2, 2, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "v1 verify columns on CRDs in json;stream=watch",
accept: "application/json;stream=watch;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-5"}}}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("unable to create cr: %v", err)
}
if _, err := crclient.Patch("test-5", types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`), metav1.PatchOptions{}); err != nil {
t.Fatalf("unable to patch cr: %v", err)
}
return cr, crdGVR.Group, "foos"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableV1WatchEvents(t, 2, 2, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "v1 verify columns on CRDs in yaml",
accept: "application/yaml;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
cr, err := crclient.Create(&unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "cr.bar.com/v1", "kind": "Foo", "metadata": map[string]interface{}{"name": "test-6"}}}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("unable to create cr: %v", err)
}
if _, err := crclient.Patch("test-6", types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`), metav1.PatchOptions{}); err != nil {
t.Fatalf("unable to patch cr: %v", err)
}
return cr, crdGVR.Group, "foos"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsNotAcceptable(err) {
t.Fatal(err)
}
// TODO: this should be a more specific error
if err.Error() != "only the following media types are accepted: application/json;stream=watch" {
t.Fatal(err)
}
},
},
{
name: "v1 verify columns on services",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
svc, err := clientset.CoreV1().Services(ns).Create(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "test-4"}, Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1000}}}})
if err != nil {
t.Fatalf("unable to create service: %v", err)
}
if _, err := clientset.CoreV1().Services(ns).Patch(svc.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`)); err != nil {
t.Fatalf("unable to update service: %v", err)
}
return svc, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableV1WatchEvents(t, 2, 7, metav1.IncludeMetadata, json.NewDecoder(w))
},
},
{
name: "v1 verify columns on services with no object",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
includeObject: metav1.IncludeNone,
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().Services(ns).Create(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "test-5"}, Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1000}}}})
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
if _, err := clientset.CoreV1().Services(ns).Patch(obj.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`)); err != nil {
t.Fatalf("unable to update object: %v", err)
}
return obj, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
expectTableV1WatchEvents(t, 2, 7, metav1.IncludeNone, json.NewDecoder(w))
},
},
{
name: "v1 verify columns on services with full object",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
includeObject: metav1.IncludeObject,
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().Services(ns).Create(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "test-6"}, Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1000}}}})
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
if _, err := clientset.CoreV1().Services(ns).Patch(obj.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`)); err != nil {
t.Fatalf("unable to update object: %v", err)
}
return obj, "", "services"
},
wantBody: func(t *testing.T, w io.Reader) {
objects := expectTableV1WatchEvents(t, 2, 7, metav1.IncludeObject, json.NewDecoder(w))
var svc v1.Service
if err := json.Unmarshal(objects[1], &svc); err != nil {
t.Fatal(err)
}
if svc.Annotations["test"] != "1" || svc.Spec.Ports[0].Port != 1000 {
t.Fatalf("unexpected object: %#v", svc)
}
},
},
{
name: "v1 verify partial metadata object on config maps",
accept: "application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().ConfigMaps(ns).Create(&v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "test-3", Annotations: map[string]string{"test": "0"}}})
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
if _, err := clientset.CoreV1().ConfigMaps(ns).Patch(obj.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`)); err != nil {
t.Fatalf("unable to update object: %v", err)
}
return obj, "", "configmaps"
},
wantBody: func(t *testing.T, w io.Reader) {
expectPartialObjectMetaV1Events(t, json.NewDecoder(w), "0", "1")
},
},
{
name: "v1 verify partial metadata object on config maps in protobuf",
accept: "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
ns := "default"
obj, err := clientset.CoreV1().ConfigMaps(ns).Create(&v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "test-4", Annotations: map[string]string{"test": "0"}}})
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
if _, err := clientset.CoreV1().ConfigMaps(ns).Patch(obj.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"test":"1"}}}`)); err != nil {
t.Fatalf("unable to update object: %v", err)
}
return obj, "", "configmaps"
},
wantBody: func(t *testing.T, w io.Reader) {
expectPartialObjectMetaV1EventsProtobuf(t, w, "0", "1")
},
},
{
name: "v1 verify error on unsupported mimetype protobuf for table conversion",
accept: "application/vnd.kubernetes.protobuf;as=Table;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsNotAcceptable(err) {
t.Fatal(err)
}
// TODO: this should be a more specific error
if err.Error() != "only the following media types are accepted: application/json, application/yaml, application/vnd.kubernetes.protobuf" {
t.Fatal(err)
}
},
},
{
name: "v1 verify error on invalid mimetype - bad group",
accept: "application/json;as=PartialObjectMetadata;g=k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsNotAcceptable(err) {
t.Fatal(err)
}
},
},
{
name: "v1 verify error on invalid mimetype - bad kind",
accept: "application/json;as=PartialObject;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsNotAcceptable(err) {
t.Fatal(err)
}
},
},
{
name: "v1 verify error on invalid mimetype - missing kind",
accept: "application/json;g=meta.k8s.io;v=v1",
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
wantErr: func(t *testing.T, err error) {
if !apierrors.IsNotAcceptable(err) {
t.Fatal(err)
}
},
},
{
name: "v1 verify error on invalid transform parameter",
accept: "application/json;as=Table;g=meta.k8s.io;v=v1",
includeObject: metav1.IncludeObjectPolicy("unrecognized"),
object: func(t *testing.T) (metav1.Object, string, string) {
return &metav1.ObjectMeta{Name: "kubernetes", Namespace: "default"}, "", "services"
},
@@ -892,7 +1124,7 @@ func TestTransformOnWatch(t *testing.T) {
}
}
func expectTableWatchEvents(t *testing.T, count, columns int, policy metav1beta1.IncludeObjectPolicy, d *json.Decoder) [][]byte {
func expectTableWatchEvents(t *testing.T, count, columns int, policy metav1.IncludeObjectPolicy, d *json.Decoder) [][]byte {
t.Helper()
var objects [][]byte
@@ -923,7 +1155,7 @@ func expectTableWatchEvents(t *testing.T, count, columns int, policy metav1beta1
t.Fatalf("Invalid row width: %#v", row.Cells)
}
switch policy {
case metav1beta1.IncludeMetadata:
case metav1.IncludeMetadata:
var meta metav1beta1.PartialObjectMetadata
if err := json.Unmarshal(row.Object.Raw, &meta); err != nil {
t.Fatalf("expected partial object: %v", err)
@@ -932,11 +1164,11 @@ func expectTableWatchEvents(t *testing.T, count, columns int, policy metav1beta1
if meta.TypeMeta != partialObj {
t.Fatalf("expected partial object: %#v", meta)
}
case metav1beta1.IncludeNone:
case metav1.IncludeNone:
if len(row.Object.Raw) != 0 {
t.Fatalf("Expected no object: %s", string(row.Object.Raw))
}
case metav1beta1.IncludeObject:
case metav1.IncludeObject:
if len(row.Object.Raw) == 0 {
t.Fatalf("Expected object: %s", string(row.Object.Raw))
}
@@ -1000,3 +1232,112 @@ func expectPartialObjectMetaEventsProtobuf(t *testing.T, r io.Reader, values ...
}
}
}
func expectTableV1WatchEvents(t *testing.T, count, columns int, policy metav1.IncludeObjectPolicy, d *json.Decoder) [][]byte {
t.Helper()
var objects [][]byte
for i := 0; i < count; i++ {
var evt metav1.WatchEvent
if err := d.Decode(&evt); err != nil {
t.Fatal(err)
}
var table metav1.Table
if err := json.Unmarshal(evt.Object.Raw, &table); err != nil {
t.Fatal(err)
}
if i == 0 {
if len(table.ColumnDefinitions) != columns {
t.Fatalf("Got unexpected columns on first watch event: %d vs %#v", columns, table.ColumnDefinitions)
}
} else {
if len(table.ColumnDefinitions) != 0 {
t.Fatalf("Expected no columns on second watch event: %#v", table.ColumnDefinitions)
}
}
if len(table.Rows) != 1 {
t.Fatalf("Invalid rows: %#v", table.Rows)
}
row := table.Rows[0]
if len(row.Cells) != columns {
t.Fatalf("Invalid row width: %#v", row.Cells)
}
switch policy {
case metav1.IncludeMetadata:
var meta metav1.PartialObjectMetadata
if err := json.Unmarshal(row.Object.Raw, &meta); err != nil {
t.Fatalf("expected partial object: %v", err)
}
partialObj := metav1.TypeMeta{Kind: "PartialObjectMetadata", APIVersion: "meta.k8s.io/v1"}
if meta.TypeMeta != partialObj {
t.Fatalf("expected partial object: %#v", meta)
}
case metav1.IncludeNone:
if len(row.Object.Raw) != 0 {
t.Fatalf("Expected no object: %s", string(row.Object.Raw))
}
case metav1.IncludeObject:
if len(row.Object.Raw) == 0 {
t.Fatalf("Expected object: %s", string(row.Object.Raw))
}
objects = append(objects, row.Object.Raw)
}
}
return objects
}
func expectPartialObjectMetaV1Events(t *testing.T, d *json.Decoder, values ...string) {
t.Helper()
for i, value := range values {
var evt metav1.WatchEvent
if err := d.Decode(&evt); err != nil {
t.Fatal(err)
}
var meta metav1.PartialObjectMetadata
if err := json.Unmarshal(evt.Object.Raw, &meta); err != nil {
t.Fatal(err)
}
typeMeta := metav1.TypeMeta{Kind: "PartialObjectMetadata", APIVersion: "meta.k8s.io/v1"}
if meta.TypeMeta != typeMeta {
t.Fatalf("expected partial object: %#v", meta)
}
if meta.Annotations["test"] != value {
t.Fatalf("expected event %d to have value %q instead of %q", i+1, value, meta.Annotations["test"])
}
}
}
func expectPartialObjectMetaV1EventsProtobuf(t *testing.T, r io.Reader, values ...string) {
scheme := runtime.NewScheme()
metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
rs := protobuf.NewRawSerializer(scheme, scheme)
d := streaming.NewDecoder(
protobuf.LengthDelimitedFramer.NewFrameReader(ioutil.NopCloser(r)),
rs,
)
ds := metainternalversion.Codecs.UniversalDeserializer()
for i, value := range values {
var evt metav1.WatchEvent
if _, _, err := d.Decode(nil, &evt); err != nil {
t.Fatal(err)
}
obj, gvk, err := ds.Decode(evt.Object.Raw, nil, nil)
if err != nil {
t.Fatal(err)
}
meta, ok := obj.(*metav1.PartialObjectMetadata)
if !ok {
t.Fatalf("unexpected watch object %T", obj)
}
expected := &schema.GroupVersionKind{Kind: "PartialObjectMetadata", Version: "v1", Group: "meta.k8s.io"}
if !reflect.DeepEqual(expected, gvk) {
t.Fatalf("expected partial object: %#v", meta)
}
if meta.Annotations["test"] != value {
t.Fatalf("expected event %d to have value %q instead of %q", i+1, value, meta.Annotations["test"])
}
}
}