forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request kubernetes#17156 from feihujiang/moveListFunctions…
…FromRuntimeToMetaPackage Auto commit by PR queue bot
- Loading branch information
Showing
17 changed files
with
387 additions
and
331 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
Copyright 2015 The Kubernetes Authors All rights reserved. | ||
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 meta | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
|
||
"k8s.io/kubernetes/pkg/conversion" | ||
"k8s.io/kubernetes/pkg/runtime" | ||
) | ||
|
||
// IsListType returns true if the provided Object has a slice called Items | ||
func IsListType(obj runtime.Object) bool { | ||
_, err := GetItemsPtr(obj) | ||
return err == nil | ||
} | ||
|
||
// GetItemsPtr returns a pointer to the list object's Items member. | ||
// If 'list' doesn't have an Items member, it's not really a list type | ||
// and an error will be returned. | ||
// This function will either return a pointer to a slice, or an error, but not both. | ||
func GetItemsPtr(list runtime.Object) (interface{}, error) { | ||
v, err := conversion.EnforcePtr(list) | ||
if err != nil { | ||
return nil, err | ||
} | ||
items := v.FieldByName("Items") | ||
if !items.IsValid() { | ||
return nil, fmt.Errorf("no Items field in %#v", list) | ||
} | ||
switch items.Kind() { | ||
case reflect.Interface, reflect.Ptr: | ||
target := reflect.TypeOf(items.Interface()).Elem() | ||
if target.Kind() != reflect.Slice { | ||
return nil, fmt.Errorf("items: Expected slice, got %s", target.Kind()) | ||
} | ||
return items.Interface(), nil | ||
case reflect.Slice: | ||
return items.Addr().Interface(), nil | ||
default: | ||
return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind()) | ||
} | ||
} | ||
|
||
// ExtractList returns obj's Items element as an array of runtime.Objects. | ||
// Returns an error if obj is not a List type (does not have an Items member). | ||
func ExtractList(obj runtime.Object) ([]runtime.Object, error) { | ||
itemsPtr, err := GetItemsPtr(obj) | ||
if err != nil { | ||
return nil, err | ||
} | ||
items, err := conversion.EnforcePtr(itemsPtr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
list := make([]runtime.Object, items.Len()) | ||
for i := range list { | ||
raw := items.Index(i) | ||
switch item := raw.Interface().(type) { | ||
case runtime.Object: | ||
list[i] = item | ||
case runtime.RawExtension: | ||
list[i] = &runtime.Unknown{ | ||
RawJSON: item.RawJSON, | ||
} | ||
default: | ||
var found bool | ||
if list[i], found = raw.Addr().Interface().(runtime.Object); !found { | ||
return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind()) | ||
} | ||
} | ||
} | ||
return list, nil | ||
} | ||
|
||
// objectSliceType is the type of a slice of Objects | ||
var objectSliceType = reflect.TypeOf([]runtime.Object{}) | ||
|
||
// SetList sets the given list object's Items member have the elements given in | ||
// objects. | ||
// Returns an error if list is not a List type (does not have an Items member), | ||
// or if any of the objects are not of the right type. | ||
func SetList(list runtime.Object, objects []runtime.Object) error { | ||
itemsPtr, err := GetItemsPtr(list) | ||
if err != nil { | ||
return err | ||
} | ||
items, err := conversion.EnforcePtr(itemsPtr) | ||
if err != nil { | ||
return err | ||
} | ||
if items.Type() == objectSliceType { | ||
items.Set(reflect.ValueOf(objects)) | ||
return nil | ||
} | ||
slice := reflect.MakeSlice(items.Type(), len(objects), len(objects)) | ||
for i := range objects { | ||
dest := slice.Index(i) | ||
src, err := conversion.EnforcePtr(objects[i]) | ||
if err != nil { | ||
return err | ||
} | ||
if src.Type().AssignableTo(dest.Type()) { | ||
dest.Set(src) | ||
} else if src.Type().ConvertibleTo(dest.Type()) { | ||
dest.Set(src.Convert(dest.Type())) | ||
} else { | ||
return fmt.Errorf("item[%d]: Type mismatch: Expected %v, got %v", i, dest.Type(), src.Type()) | ||
} | ||
} | ||
items.Set(slice) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/* | ||
Copyright 2014 The Kubernetes Authors All rights reserved. | ||
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 meta_test | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"k8s.io/kubernetes/pkg/api" | ||
"k8s.io/kubernetes/pkg/api/meta" | ||
"k8s.io/kubernetes/pkg/api/v1" | ||
"k8s.io/kubernetes/pkg/runtime" | ||
"k8s.io/kubernetes/pkg/util" | ||
|
||
"github.com/google/gofuzz" | ||
) | ||
|
||
func TestIsList(t *testing.T) { | ||
tests := []struct { | ||
obj runtime.Object | ||
isList bool | ||
}{ | ||
{&api.PodList{}, true}, | ||
{&api.Pod{}, false}, | ||
} | ||
for _, item := range tests { | ||
if e, a := item.isList, meta.IsListType(item.obj); e != a { | ||
t.Errorf("%v: Expected %v, got %v", reflect.TypeOf(item.obj), e, a) | ||
} | ||
} | ||
} | ||
|
||
func TestExtractList(t *testing.T) { | ||
pl := &api.PodList{ | ||
Items: []api.Pod{ | ||
{ObjectMeta: api.ObjectMeta{Name: "1"}}, | ||
{ObjectMeta: api.ObjectMeta{Name: "2"}}, | ||
{ObjectMeta: api.ObjectMeta{Name: "3"}}, | ||
}, | ||
} | ||
list, err := meta.ExtractList(pl) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
for i := range list { | ||
if e, a := list[i].(*api.Pod).Name, pl.Items[i].Name; e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
} | ||
} | ||
|
||
func TestExtractListGeneric(t *testing.T) { | ||
pl := &api.List{ | ||
Items: []runtime.Object{ | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, | ||
&api.Service{ObjectMeta: api.ObjectMeta{Name: "2"}}, | ||
}, | ||
} | ||
list, err := meta.ExtractList(pl) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
if obj, ok := list[0].(*api.Pod); !ok { | ||
t.Fatalf("Expected list[0] to be *api.Pod, it is %#v", obj) | ||
} | ||
if obj, ok := list[1].(*api.Service); !ok { | ||
t.Fatalf("Expected list[1] to be *api.Service, it is %#v", obj) | ||
} | ||
} | ||
|
||
func TestExtractListGenericV1(t *testing.T) { | ||
pl := &v1.List{ | ||
Items: []runtime.RawExtension{ | ||
{RawJSON: []byte("foo")}, | ||
{RawJSON: []byte("bar")}, | ||
}, | ||
} | ||
list, err := meta.ExtractList(pl) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
if obj, ok := list[0].(*runtime.Unknown); !ok { | ||
t.Fatalf("Expected list[0] to be *runtime.Unknown, it is %#v", obj) | ||
} | ||
if obj, ok := list[1].(*runtime.Unknown); !ok { | ||
t.Fatalf("Expected list[1] to be *runtime.Unknown, it is %#v", obj) | ||
} | ||
} | ||
|
||
type fakePtrInterfaceList struct { | ||
Items *[]runtime.Object | ||
} | ||
|
||
func (f fakePtrInterfaceList) IsAnAPIObject() {} | ||
|
||
func TestExtractListOfInterfacePtrs(t *testing.T) { | ||
pl := &fakePtrInterfaceList{ | ||
Items: &[]runtime.Object{}, | ||
} | ||
list, err := meta.ExtractList(pl) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if len(list) > 0 { | ||
t.Fatalf("Expected empty list, got %#v", list) | ||
} | ||
} | ||
|
||
type fakePtrValueList struct { | ||
Items []*api.Pod | ||
} | ||
|
||
func (f fakePtrValueList) IsAnAPIObject() {} | ||
|
||
func TestExtractListOfValuePtrs(t *testing.T) { | ||
pl := &fakePtrValueList{ | ||
Items: []*api.Pod{ | ||
{ObjectMeta: api.ObjectMeta{Name: "1"}}, | ||
{ObjectMeta: api.ObjectMeta{Name: "2"}}, | ||
}, | ||
} | ||
list, err := meta.ExtractList(pl) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
for i := range list { | ||
if obj, ok := list[i].(*api.Pod); !ok { | ||
t.Fatalf("Expected list[%d] to be *api.Pod, it is %#v", i, obj) | ||
} | ||
} | ||
} | ||
|
||
func TestSetList(t *testing.T) { | ||
pl := &api.PodList{} | ||
list := []runtime.Object{ | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}}, | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}}, | ||
} | ||
err := meta.SetList(pl, list) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
for i := range list { | ||
if e, a := list[i].(*api.Pod).Name, pl.Items[i].Name; e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
} | ||
} | ||
|
||
func TestSetListToRuntimeObjectArray(t *testing.T) { | ||
pl := &api.List{} | ||
list := []runtime.Object{ | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}}, | ||
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}}, | ||
} | ||
err := meta.SetList(pl, list) | ||
if err != nil { | ||
t.Fatalf("Unexpected error %v", err) | ||
} | ||
if e, a := len(list), len(pl.Items); e != a { | ||
t.Fatalf("Expected %v, got %v", e, a) | ||
} | ||
for i := range list { | ||
if e, a := list[i], pl.Items[i]; e != a { | ||
t.Fatalf("%d: unmatched: %s", i, util.ObjectDiff(e, a)) | ||
} | ||
} | ||
} | ||
|
||
func TestSetExtractListRoundTrip(t *testing.T) { | ||
fuzzer := fuzz.New().NilChance(0).NumElements(1, 5) | ||
for i := 0; i < 5; i++ { | ||
start := &api.PodList{} | ||
fuzzer.Fuzz(&start.Items) | ||
|
||
list, err := meta.ExtractList(start) | ||
if err != nil { | ||
t.Errorf("Unexpected error %v", err) | ||
continue | ||
} | ||
got := &api.PodList{} | ||
err = meta.SetList(got, list) | ||
if err != nil { | ||
t.Errorf("Unexpected error %v", err) | ||
continue | ||
} | ||
if e, a := start, got; !reflect.DeepEqual(e, a) { | ||
t.Fatalf("Expected %#v, got %#v", e, a) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.