Skip to content

Commit

Permalink
List objects in deterministic order
Browse files Browse the repository at this point in the history
  • Loading branch information
ddysher committed Jan 27, 2015
1 parent 60eba74 commit d30da9a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 8 deletions.
2 changes: 1 addition & 1 deletion pkg/tools/etcd_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func etcdErrorIndex(err error) (uint64, bool) {
}

func (h *EtcdHelper) listEtcdNode(key string) ([]*etcd.Node, uint64, error) {
result, err := h.Client.Get(key, false, true)
result, err := h.Client.Get(key, true, true)
if err != nil {
index, ok := etcdErrorIndex(err)
if !ok {
Expand Down
36 changes: 29 additions & 7 deletions pkg/tools/etcd_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ import (
"github.com/coreos/go-etcd/etcd"
)

type fakeClientGetSet struct {
get func(key string, sort, recursive bool) (*etcd.Response, error)
set func(key, value string, ttl uint64) (*etcd.Response, error)
}

type TestResource struct {
api.TypeMeta `json:",inline"`
api.ObjectMeta `json:"metadata"`
Expand Down Expand Up @@ -72,17 +67,24 @@ func TestExtractToList(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 2,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 3,
},
},
Expand All @@ -92,9 +94,10 @@ func TestExtractToList(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
// We expect items to be sorted by its name.
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
},
}

Expand All @@ -116,22 +119,34 @@ func TestExtractToListAcrossDirectories(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/directory1",
Value: `{"name": "directory1"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
},
},
{
Key: "/directory2",
Value: `{"name": "directory2"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 2,
},
Expand All @@ -144,6 +159,8 @@ func TestExtractToListAcrossDirectories(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
// We expect list to be sorted by directory (e.g. namespace) first, then by name.
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
},
Expand All @@ -166,20 +183,25 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 1,
},
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 2,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 3,
},
{
Key: "/directory",
Value: `{"name": "directory"}`,
Dir: true,
},
Expand All @@ -190,9 +212,9 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
},
}

Expand Down
15 changes: 15 additions & 0 deletions pkg/tools/fake_etcd_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package tools
import (
"errors"
"fmt"
"sort"
"sync"

"github.com/coreos/go-etcd/etcd"
Expand Down Expand Up @@ -132,9 +133,23 @@ func (f *FakeEtcdClient) Get(key string, sort, recursive bool) (*etcd.Response,
return &etcd.Response{}, EtcdErrorNotFound
}
f.t.Logf("returning %v: %#v %#v", key, result.R, result.E)

// Sort response, note this will alter resutl.R.
if result.R.Node != nil && result.R.Node.Nodes != nil && sort {
f.sortResponse(result.R.Node.Nodes)
}
return result.R, result.E
}

func (f *FakeEtcdClient) sortResponse(nodes etcd.Nodes) {
for i := range nodes {
if nodes[i].Dir {
f.sortResponse(nodes[i].Nodes)
}
}
sort.Sort(nodes)
}

func (f *FakeEtcdClient) nodeExists(key string) bool {
result, ok := f.Data[key]
return ok && result.R != nil && result.R.Node != nil && result.E == nil
Expand Down

0 comments on commit d30da9a

Please sign in to comment.