Skip to content

Commit

Permalink
Extract list must flatten nodes across directories
Browse files Browse the repository at this point in the history
  • Loading branch information
derekwaynecarr committed Oct 16, 2014
1 parent 3436775 commit b63974b
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 9 deletions.
28 changes: 19 additions & 9 deletions pkg/tools/etcd_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,23 +164,33 @@ 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.
panic("need ptr to slice")
}
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 err != nil {
return err
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()))
}
v.Set(reflect.Append(v, obj.Elem()))
}
return nil
}
Expand Down
98 changes: 98 additions & 0 deletions pkg/tools/etcd_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}
Expand Down

0 comments on commit b63974b

Please sign in to comment.