Extract list must flatten nodes across directories

This commit is contained in:
derekwaynecarr
2014-10-03 11:23:25 -04:00
parent 343677580a
commit b63974bd21
2 changed files with 117 additions and 9 deletions

View File

@@ -164,6 +164,12 @@ func (h *EtcdHelper) ExtractList(key string, slicePtr interface{}, resourceVersi
if err != nil {
return err
}
h.decodeNodeList(nodes, slicePtr)
return nil
}
// decodeNodeList walks the tree of each node in the list and decodes into the specified object
func (h *EtcdHelper) decodeNodeList(nodes []*etcd.Node, slicePtr interface{}) error {
pv := reflect.ValueOf(slicePtr)
if pv.Type().Kind() != reflect.Ptr || pv.Type().Elem().Kind() != reflect.Slice {
// This should not happen at runtime.
@@ -171,16 +177,20 @@ func (h *EtcdHelper) ExtractList(key string, slicePtr interface{}, resourceVersi
}
v := pv.Elem()
for _, node := range nodes {
obj := reflect.New(v.Type().Elem())
err = h.Codec.DecodeInto([]byte(node.Value), obj.Interface().(runtime.Object))
if h.ResourceVersioner != nil {
_ = h.ResourceVersioner.SetResourceVersion(obj.Interface().(runtime.Object), node.ModifiedIndex)
// being unable to set the version does not prevent the object from being extracted
if node.Dir {
h.decodeNodeList(node.Nodes, slicePtr)
} else {
obj := reflect.New(v.Type().Elem())
err := h.Codec.DecodeInto([]byte(node.Value), obj.Interface().(runtime.Object))
if h.ResourceVersioner != nil {
_ = h.ResourceVersioner.SetResourceVersion(obj.Interface().(runtime.Object), node.ModifiedIndex)
// being unable to set the version does not prevent the object from being extracted
}
if err != nil {
return err
}
v.Set(reflect.Append(v, obj.Elem()))
}
if err != nil {
return err
}
v.Set(reflect.Append(v, obj.Elem()))
}
return nil
}

View File

@@ -108,6 +108,104 @@ func TestExtractToList(t *testing.T) {
}
}
// TestExtractToListAcrossDirectories ensures that the client excludes directories and flattens tree-response - simulates cross-namespace query
func TestExtractToListAcrossDirectories(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = EtcdResponseWithError{
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: `{"id": "directory1"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Value: `{"id":"foo"}`,
ModifiedIndex: 1,
},
},
},
{
Value: `{"id": "directory2"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Value: `{"id":"bar"}`,
ModifiedIndex: 2,
},
},
},
},
},
},
}
expect := api.PodList{
JSONBase: api.JSONBase{ResourceVersion: 10},
Items: []api.Pod{
{JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1}},
{JSONBase: api.JSONBase{ID: "bar", ResourceVersion: 2}},
},
}
var got api.PodList
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
err := helper.ExtractToList("/some/key", &got)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
if e, a := expect, got; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
}
func TestExtractToListExcludesDirectories(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = EtcdResponseWithError{
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: `{"id":"foo"}`,
ModifiedIndex: 1,
},
{
Value: `{"id":"bar"}`,
ModifiedIndex: 2,
},
{
Value: `{"id":"baz"}`,
ModifiedIndex: 3,
},
{
Value: `{"id": "directory"}`,
Dir: true,
},
},
},
},
}
expect := api.PodList{
JSONBase: api.JSONBase{ResourceVersion: 10},
Items: []api.Pod{
{JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1}},
{JSONBase: api.JSONBase{ID: "bar", ResourceVersion: 2}},
{JSONBase: api.JSONBase{ID: "baz", ResourceVersion: 3}},
},
}
var got api.PodList
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
err := helper.ExtractToList("/some/key", &got)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
if e, a := expect, got; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
}
func TestExtractObj(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
expect := api.Pod{TypeMeta: api.TypeMeta{ID: "foo"}}