ソースを参照

Merge pull request #264 from mavenugo/mh-ln

datastore support for endpoint, GetObject, DeleteObject and swarm store API upgrade
Jana Radhakrishnan 10 年 前
コミット
fb06bd5a1a
86 ファイル変更14914 行追加916 行削除
  1. 4 4
      libnetwork/Godeps/Godeps.json
  2. 4 4
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/README.md
  3. 79 19
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery.go
  4. 72 6
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery_test.go
  5. 49 11
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file.go
  6. 64 4
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file_test.go
  7. 93 45
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv.go
  8. 80 6
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv_test.go
  9. 16 8
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes.go
  10. 29 17
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes_test.go
  11. 50 11
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token.go
  12. 22 10
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token_test.go
  13. 25 21
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/README.md
  14. 264 162
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul.go
  15. 69 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul_test.go
  16. 288 108
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd.go
  17. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd_test.go
  18. 15 20
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/helpers.go
  19. 109 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/mock.go
  20. 107 45
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store.go
  21. 401 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store_test.go
  22. 0 60
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/structs.go
  23. 192 94
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper.go
  24. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper_test.go
  25. 22 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/.gitignore
  26. 23 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/LICENSE.md
  27. 3 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/README.md
  28. 179 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors.go
  29. 145 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go
  30. 14 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/array-access.txt
  31. 86 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/index.html
  32. 286 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/template.txt
  33. 20 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/types_list.txt
  34. 13 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/constants.go
  35. 117 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions.go
  36. 94 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go
  37. 72 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/doc.go
  38. 98 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go
  39. 222 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map.go
  40. 10 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_for_test.go
  41. 147 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go
  42. 81 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations.go
  43. 77 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations_test.go
  44. 14 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security.go
  45. 12 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security_test.go
  46. 41 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/simple_example_test.go
  47. 17 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests.go
  48. 24 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests_test.go
  49. 2881 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen.go
  50. 2867 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen_test.go
  51. 13 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value.go
  52. 1 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value_test.go
  53. 853 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go
  54. 791 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions_test.go
  55. 154 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/doc.go
  56. 10 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/errors.go
  57. 265 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go
  58. 511 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions_test.go
  59. 157 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go
  60. 86 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions_test.go
  61. 43 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go
  62. 566 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go
  63. 843 0
      libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock_test.go
  64. 5 0
      libnetwork/cmd/dnet/dnet.go
  65. 2 2
      libnetwork/cmd/test/libnetwork.toml
  66. 21 5
      libnetwork/cmd/test/main.go
  67. 59 100
      libnetwork/controller.go
  68. 69 19
      libnetwork/datastore/datastore.go
  69. 30 5
      libnetwork/datastore/datastore_test.go
  70. 35 47
      libnetwork/datastore/mock_store.go
  71. 16 1
      libnetwork/driverapi/driverapi.go
  72. 4 2
      libnetwork/drivers/bridge/bridge.go
  73. 4 1
      libnetwork/drivers/host/host.go
  74. 4 1
      libnetwork/drivers/null/null.go
  75. 4 1
      libnetwork/drivers/remote/driver.go
  76. 4 1
      libnetwork/drivers/windows/windows.go
  77. 0 2
      libnetwork/drivers_freebsd.go
  78. 0 2
      libnetwork/drivers_linux.go
  79. 0 2
      libnetwork/drivers_windows.go
  80. 190 5
      libnetwork/endpoint.go
  81. 65 11
      libnetwork/endpoint_info.go
  82. 29 25
      libnetwork/hostdiscovery/hostdiscovery.go
  83. 2 2
      libnetwork/hostdiscovery/hostdiscovery_test.go
  84. 2 2
      libnetwork/libnetwork_internal_test.go
  85. 127 25
      libnetwork/network.go
  86. 292 0
      libnetwork/store.go

+ 4 - 4
libnetwork/Godeps/Godeps.json

@@ -77,13 +77,13 @@
 		},
 		{
 			"ImportPath": "github.com/docker/swarm/discovery",
-			"Comment": "v0.2.0-333-g54dfabd",
-			"Rev": "54dfabd2521314de1c5b036f6c609efbe09df4ea"
+			"Comment": "v0.3.0-rc2",
+			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
 		},
 		{
 			"ImportPath": "github.com/docker/swarm/pkg/store",
-			"Comment": "v0.2.0-333-g54dfabd",
-			"Rev": "54dfabd2521314de1c5b036f6c609efbe09df4ea"
+			"Comment": "v0.3.0-rc2",
+			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
 		},
 		{
 			"ImportPath": "github.com/godbus/dbus",

+ 4 - 4
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/README.md

@@ -26,7 +26,7 @@ Then we create each node and join them to the cluster.
 # on each of your nodes, start the swarm agent
 #  <node_ip> doesn't have to be public (eg. 192.168.0.X),
 #  as long as the swarm manager can access it.
-$ swarm join --addr=<node_ip:2375> token://<cluster_id>
+$ swarm join --advertise=<node_ip:2375> token://<cluster_id>
 ```
 
 Finally, we start the Swarm manager. This can be on any machine or even
@@ -95,7 +95,7 @@ On each of your nodes, start the Swarm agent. The node IP address
 doesn't have to be public as long as the swarm manager can access it.
 
 ```bash
-swarm join --addr=<node_ip:2375> etcd://<etcd_ip>/<path>
+swarm join --advertise=<node_ip:2375> etcd://<etcd_ip>/<path>
 ```
 
 Start the manager on any machine or your laptop.
@@ -127,7 +127,7 @@ On each of your nodes, start the Swarm agent. The node IP address
 doesn't need to be public as long as the Swarm manager can access it.
 
 ```bash
-swarm join --addr=<node_ip:2375> consul://<consul_addr>/<path>
+swarm join --advertise=<node_ip:2375> consul://<consul_addr>/<path>
 ```
 
 Start the manager on any machine or your laptop.
@@ -159,7 +159,7 @@ On each of your nodes, start the Swarm agent. The node IP doesn't have
 to be public as long as the swarm manager can access it.
 
 ```bash
-swarm join --addr=<node_ip:2375> zk://<zookeeper_addr1>,<zookeeper_addr2>/<path>
+swarm join --advertise=<node_ip:2375> zk://<zookeeper_addr1>,<zookeeper_addr2>/<path>
 ```
 
 Start the manager on any machine or your laptop.

+ 79 - 19
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery.go

@@ -5,17 +5,18 @@ import (
 	"fmt"
 	"net"
 	"strings"
+	"time"
 
 	log "github.com/Sirupsen/logrus"
 )
 
-// Entry is exported
+// An Entry represents a swarm host.
 type Entry struct {
 	Host string
 	Port string
 }
 
-// NewEntry is exported
+// NewEntry creates a new entry.
 func NewEntry(url string) (*Entry, error) {
 	host, port, err := net.SplitHostPort(url)
 	if err != nil {
@@ -24,26 +25,83 @@ func NewEntry(url string) (*Entry, error) {
 	return &Entry{host, port}, nil
 }
 
-func (m Entry) String() string {
-	return fmt.Sprintf("%s:%s", m.Host, m.Port)
+// String returns the string form of an entry.
+func (e *Entry) String() string {
+	return fmt.Sprintf("%s:%s", e.Host, e.Port)
 }
 
-// WatchCallback is exported
-type WatchCallback func(entries []*Entry)
+// Equals returns true if cmp contains the same data.
+func (e *Entry) Equals(cmp *Entry) bool {
+	return e.Host == cmp.Host && e.Port == cmp.Port
+}
+
+// Entries is a list of *Entry with some helpers.
+type Entries []*Entry
+
+// Equals returns true if cmp contains the same data.
+func (e Entries) Equals(cmp Entries) bool {
+	// Check if the file has really changed.
+	if len(e) != len(cmp) {
+		return false
+	}
+	for i := range e {
+		if !e[i].Equals(cmp[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// Contains returns true if the Entries contain a given Entry.
+func (e Entries) Contains(entry *Entry) bool {
+	for _, curr := range e {
+		if curr.Equals(entry) {
+			return true
+		}
+	}
+	return false
+}
 
-// Discovery is exported
+// Diff compares two entries and returns the added and removed entries.
+func (e Entries) Diff(cmp Entries) (Entries, Entries) {
+	added := Entries{}
+	for _, entry := range cmp {
+		if !e.Contains(entry) {
+			added = append(added, entry)
+		}
+	}
+
+	removed := Entries{}
+	for _, entry := range e {
+		if !cmp.Contains(entry) {
+			removed = append(removed, entry)
+		}
+	}
+
+	return added, removed
+}
+
+// The Discovery interface is implemented by Discovery backends which
+// manage swarm host entries.
 type Discovery interface {
-	Initialize(string, uint64) error
-	Fetch() ([]*Entry, error)
-	Watch(WatchCallback)
+	// Initialize the discovery with URIs, a heartbeat and a ttl.
+	Initialize(string, time.Duration, time.Duration) error
+
+	// Watch the discovery for entry changes.
+	// Returns a channel that will receive changes or an error.
+	// Providing a non-nil stopCh can be used to stop watching.
+	Watch(stopCh <-chan struct{}) (<-chan Entries, <-chan error)
+
+	// Register to the discovery
 	Register(string) error
 }
 
 var (
 	discoveries map[string]Discovery
-	// ErrNotSupported is exported
+	// ErrNotSupported is returned when a discovery service is not supported.
 	ErrNotSupported = errors.New("discovery service not supported")
-	// ErrNotImplemented is exported
+	// ErrNotImplemented is returned when discovery feature is not implemented
+	// by discovery backend.
 	ErrNotImplemented = errors.New("not implemented in this discovery service")
 )
 
@@ -51,7 +109,8 @@ func init() {
 	discoveries = make(map[string]Discovery)
 }
 
-// Register is exported
+// Register makes a discovery backend available by the provided scheme.
+// If Register is called twice with the same scheme an error is returned.
 func Register(scheme string, d Discovery) error {
 	if _, exists := discoveries[scheme]; exists {
 		return fmt.Errorf("scheme already registered %s", scheme)
@@ -72,22 +131,23 @@ func parse(rawurl string) (string, string) {
 	return parts[0], parts[1]
 }
 
-// New is exported
-func New(rawurl string, heartbeat uint64) (Discovery, error) {
+// New returns a new Discovery given a URL, heartbeat and ttl settings.
+// Returns an error if the URL scheme is not supported.
+func New(rawurl string, heartbeat time.Duration, ttl time.Duration) (Discovery, error) {
 	scheme, uri := parse(rawurl)
 
 	if discovery, exists := discoveries[scheme]; exists {
 		log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service")
-		err := discovery.Initialize(uri, heartbeat)
+		err := discovery.Initialize(uri, heartbeat, ttl)
 		return discovery, err
 	}
 
 	return nil, ErrNotSupported
 }
 
-// CreateEntries is exported
-func CreateEntries(addrs []string) ([]*Entry, error) {
-	entries := []*Entry{}
+// CreateEntries returns an array of entries based on the given addresses.
+func CreateEntries(addrs []string) (Entries, error) {
+	entries := Entries{}
 	if addrs == nil {
 		return entries, nil
 	}

+ 72 - 6
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/discovery_test.go

@@ -8,9 +8,9 @@ import (
 
 func TestNewEntry(t *testing.T) {
 	entry, err := NewEntry("127.0.0.1:2375")
-	assert.Equal(t, entry.Host, "127.0.0.1")
-	assert.Equal(t, entry.Port, "2375")
 	assert.NoError(t, err)
+	assert.True(t, entry.Equals(&Entry{Host: "127.0.0.1", Port: "2375"}))
+	assert.Equal(t, entry.String(), "127.0.0.1:2375")
 
 	_, err = NewEntry("127.0.0.1")
 	assert.Error(t, err)
@@ -40,15 +40,81 @@ func TestParse(t *testing.T) {
 
 func TestCreateEntries(t *testing.T) {
 	entries, err := CreateEntries(nil)
-	assert.Equal(t, entries, []*Entry{})
+	assert.Equal(t, entries, Entries{})
 	assert.NoError(t, err)
 
 	entries, err = CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""})
-	assert.Equal(t, len(entries), 2)
-	assert.Equal(t, entries[0].String(), "127.0.0.1:2375")
-	assert.Equal(t, entries[1].String(), "127.0.0.2:2375")
 	assert.NoError(t, err)
+	expected := Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}
+	assert.True(t, entries.Equals(expected))
 
 	_, err = CreateEntries([]string{"127.0.0.1", "127.0.0.2"})
 	assert.Error(t, err)
 }
+
+func TestContainsEntry(t *testing.T) {
+	entries, err := CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""})
+	assert.NoError(t, err)
+	assert.True(t, entries.Contains(&Entry{Host: "127.0.0.1", Port: "2375"}))
+	assert.False(t, entries.Contains(&Entry{Host: "127.0.0.3", Port: "2375"}))
+}
+
+func TestEntriesEquality(t *testing.T) {
+	entries := Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}
+
+	// Same
+	assert.True(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+	}))
+
+	// Different size
+	assert.False(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.2", Port: "2375"},
+		&Entry{Host: "127.0.0.3", Port: "2375"},
+	}))
+
+	// Different content
+	assert.False(t, entries.Equals(Entries{
+		&Entry{Host: "127.0.0.1", Port: "2375"},
+		&Entry{Host: "127.0.0.42", Port: "2375"},
+	}))
+}
+
+func TestEntriesDiff(t *testing.T) {
+	entry1 := &Entry{Host: "1.1.1.1", Port: "1111"}
+	entry2 := &Entry{Host: "2.2.2.2", Port: "2222"}
+	entry3 := &Entry{Host: "3.3.3.3", Port: "3333"}
+	entries := Entries{entry1, entry2}
+
+	// No diff
+	added, removed := entries.Diff(Entries{entry2, entry1})
+	assert.Empty(t, added)
+	assert.Empty(t, removed)
+
+	// Add
+	added, removed = entries.Diff(Entries{entry2, entry3, entry1})
+	assert.Len(t, added, 1)
+	assert.True(t, added.Contains(entry3))
+	assert.Empty(t, removed)
+
+	// Remove
+	added, removed = entries.Diff(Entries{entry2})
+	assert.Empty(t, added)
+	assert.Len(t, removed, 1)
+	assert.True(t, removed.Contains(entry1))
+
+	// Add and remove
+	added, removed = entries.Diff(Entries{entry1, entry3})
+	assert.Len(t, added, 1)
+	assert.True(t, added.Contains(entry3))
+	assert.Len(t, removed, 1)
+	assert.True(t, removed.Contains(entry2))
+}

+ 49 - 11
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file.go

@@ -1,6 +1,7 @@
 package file
 
 import (
+	"fmt"
 	"io/ioutil"
 	"strings"
 	"time"
@@ -10,16 +11,21 @@ import (
 
 // Discovery is exported
 type Discovery struct {
-	heartbeat uint64
+	heartbeat time.Duration
 	path      string
 }
 
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("file", &Discovery{})
 }
 
 // Initialize is exported
-func (s *Discovery) Initialize(path string, heartbeat uint64) error {
+func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration) error {
 	s.path = path
 	s.heartbeat = heartbeat
 	return nil
@@ -46,23 +52,55 @@ func parseFileContent(content []byte) []string {
 	return result
 }
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
+func (s *Discovery) fetch() (discovery.Entries, error) {
 	fileContent, err := ioutil.ReadFile(s.path)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to read '%s': %v", s.path, err)
 	}
 	return discovery.CreateEntries(parseFileContent(fileContent))
 }
 
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
-		entries, err := s.Fetch()
-		if err == nil {
-			callback(entries)
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	errCh := make(chan error)
+	ticker := time.NewTicker(s.heartbeat)
+
+	go func() {
+		defer close(errCh)
+		defer close(ch)
+
+		// Send the initial entries if available.
+		currentEntries, err := s.fetch()
+		if err != nil {
+			errCh <- err
+		} else {
+			ch <- currentEntries
 		}
-	}
+
+		// Periodically send updates.
+		for {
+			select {
+			case <-ticker.C:
+				newEntries, err := s.fetch()
+				if err != nil {
+					errCh <- err
+					continue
+				}
+
+				// Check if the file has really changed.
+				if !newEntries.Equals(currentEntries) {
+					ch <- newEntries
+				}
+				currentEntries = newEntries
+			case <-stopCh:
+				ticker.Stop()
+				return
+			}
+		}
+	}()
+
+	return ch, errCh
 }
 
 // Register is exported

+ 64 - 4
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/file/file_test.go

@@ -1,15 +1,24 @@
 package file
 
 import (
+	"io/ioutil"
+	"os"
 	"testing"
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestInitialize(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("/path/to/file", 0)
-	assert.Equal(t, discovery.path, "/path/to/file")
+	d := &Discovery{}
+	d.Initialize("/path/to/file", 1000, 0)
+	assert.Equal(t, d.path, "/path/to/file")
+}
+
+func TestNew(t *testing.T) {
+	d, err := discovery.New("file:///path/to/file", 0, 0)
+	assert.NoError(t, err)
+	assert.Equal(t, d.(*Discovery).path, "/path/to/file")
 }
 
 func TestContent(t *testing.T) {
@@ -18,6 +27,7 @@ func TestContent(t *testing.T) {
 2.2.2.[2:4]:2222
 `
 	ips := parseFileContent([]byte(data))
+	assert.Len(t, ips, 5)
 	assert.Equal(t, ips[0], "1.1.1.1:1111")
 	assert.Equal(t, ips[1], "1.1.1.2:1111")
 	assert.Equal(t, ips[2], "2.2.2.2:2222")
@@ -40,7 +50,57 @@ func TestParsingContentsWithComments(t *testing.T) {
 ### test ###
 `
 	ips := parseFileContent([]byte(data))
-	assert.Equal(t, 2, len(ips))
+	assert.Len(t, ips, 2)
 	assert.Equal(t, "1.1.1.1:1111", ips[0])
 	assert.Equal(t, "3.3.3.3:3333", ips[1])
 }
+
+func TestWatch(t *testing.T) {
+	data := `
+1.1.1.1:1111
+2.2.2.2:2222
+`
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+
+	// Create a temporary file and remove it.
+	tmp, err := ioutil.TempFile(os.TempDir(), "discovery-file-test")
+	assert.NoError(t, err)
+	assert.NoError(t, tmp.Close())
+	assert.NoError(t, os.Remove(tmp.Name()))
+
+	// Set up file discovery.
+	d := &Discovery{}
+	d.Initialize(tmp.Name(), 1000, 0)
+	stopCh := make(chan struct{})
+	ch, errCh := d.Watch(stopCh)
+
+	// Make sure it fires errors since the file doesn't exist.
+	assert.Error(t, <-errCh)
+	// We have to drain the error channel otherwise Watch will get stuck.
+	go func() {
+		for _ = range errCh {
+		}
+	}()
+
+	// Write the file and make sure we get the expected value back.
+	assert.NoError(t, ioutil.WriteFile(tmp.Name(), []byte(data), 0600))
+	assert.Equal(t, expected, <-ch)
+
+	// Add a new entry and look it up.
+	expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"})
+	f, err := os.OpenFile(tmp.Name(), os.O_APPEND|os.O_WRONLY, 0600)
+	assert.NoError(t, err)
+	assert.NotNil(t, f)
+	_, err = f.WriteString("\n3.3.3.3:3333\n")
+	assert.NoError(t, err)
+	f.Close()
+	assert.Equal(t, expected, <-ch)
+
+	// Stop and make sure it closes all channels.
+	close(stopCh)
+	assert.Nil(t, <-ch)
+	assert.Nil(t, <-errCh)
+}

+ 93 - 45
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv.go

@@ -6,87 +6,135 @@ import (
 	"strings"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/swarm/discovery"
 	"github.com/docker/swarm/pkg/store"
 )
 
+const (
+	discoveryPath = "docker/swarm/nodes"
+)
+
 // Discovery is exported
 type Discovery struct {
+	backend   store.Backend
 	store     store.Store
-	name      string
 	heartbeat time.Duration
-	prefix    string
+	ttl       time.Duration
+	path      string
 }
 
 func init() {
-	discovery.Register("zk", &Discovery{name: "zk"})
-	discovery.Register("consul", &Discovery{name: "consul"})
-	discovery.Register("etcd", &Discovery{name: "etcd"})
+	Init()
+}
+
+// Init is exported
+func Init() {
+	discovery.Register("zk", &Discovery{backend: store.ZK})
+	discovery.Register("consul", &Discovery{backend: store.CONSUL})
+	discovery.Register("etcd", &Discovery{backend: store.ETCD})
 }
 
 // Initialize is exported
-func (s *Discovery) Initialize(uris string, heartbeat uint64) error {
+func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration) error {
 	var (
-		parts = strings.SplitN(uris, "/", 2)
-		ips   = strings.Split(parts[0], ",")
-		addrs []string
-		err   error
+		parts  = strings.SplitN(uris, "/", 2)
+		addrs  = strings.Split(parts[0], ",")
+		prefix = ""
+		err    error
 	)
 
-	if len(parts) != 2 {
-		return fmt.Errorf("invalid format %q, missing <path>", uris)
+	// A custom prefix to the path can be optionally used.
+	if len(parts) == 2 {
+		prefix = parts[1]
 	}
 
-	for _, ip := range ips {
-		addrs = append(addrs, ip)
-	}
-
-	s.heartbeat = time.Duration(heartbeat) * time.Second
-	s.prefix = parts[1]
+	s.heartbeat = heartbeat
+	s.ttl = ttl
+	s.path = path.Join(prefix, discoveryPath)
 
 	// Creates a new store, will ignore options given
 	// if not supported by the chosen store
-	s.store, err = store.CreateStore(
-		s.name, // name of the store
+	s.store, err = store.NewStore(
+		s.backend,
 		addrs,
-		store.Config{
-			Timeout: s.heartbeat,
+		&store.Config{
+			EphemeralTTL: s.ttl,
 		},
 	)
-	if err != nil {
-		return err
-	}
 
-	return nil
+	return err
 }
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-	addrs, err := s.store.GetRange(s.prefix)
-	if err != nil {
-		return nil, err
+// Watch the store until either there's a store error or we receive a stop request.
+// Returns false if we shouldn't attempt watching the store anymore (stop request received).
+func (s *Discovery) watchOnce(stopCh <-chan struct{}, watchCh <-chan []*store.KVPair, discoveryCh chan discovery.Entries, errCh chan error) bool {
+	for {
+		select {
+		case pairs := <-watchCh:
+			if pairs == nil {
+				return true
+			}
+
+			log.WithField("discovery", s.backend).Debugf("Watch triggered with %d nodes", len(pairs))
+
+			// Convert `KVPair` into `discovery.Entry`.
+			addrs := make([]string, len(pairs))
+			for _, pair := range pairs {
+				addrs = append(addrs, string(pair.Value))
+			}
+
+			entries, err := discovery.CreateEntries(addrs)
+			if err != nil {
+				errCh <- err
+			} else {
+				discoveryCh <- entries
+			}
+		case <-stopCh:
+			// We were requested to stop watching.
+			return false
+		}
 	}
-	return discovery.CreateEntries(convertToStringArray(addrs))
 }
 
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	s.store.WatchRange(s.prefix, "", s.heartbeat, func(kvalues []store.KVEntry) {
-		// Traduce byte array entries to discovery.Entry
-		entries, _ := discovery.CreateEntries(convertToStringArray(kvalues))
-		callback(entries)
-	})
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	errCh := make(chan error)
+
+	go func() {
+		defer close(ch)
+		defer close(errCh)
+
+		// Forever: Create a store watch, watch until we get an error and then try again.
+		// Will only stop if we receive a stopCh request.
+		for {
+			// Set up a watch.
+			watchCh, err := s.store.WatchTree(s.path, stopCh)
+			if err != nil {
+				errCh <- err
+			} else {
+				if !s.watchOnce(stopCh, watchCh, ch, errCh) {
+					return
+				}
+			}
+
+			// If we get here it means the store watch channel was closed. This
+			// is unexpected so let's retry later.
+			errCh <- fmt.Errorf("Unexpected watch error")
+			time.Sleep(s.heartbeat)
+		}
+	}()
+	return ch, errCh
 }
 
 // Register is exported
 func (s *Discovery) Register(addr string) error {
-	err := s.store.Put(path.Join(s.prefix, addr), []byte(addr))
-	return err
+	opts := &store.WriteOptions{Ephemeral: true, Heartbeat: s.heartbeat}
+	return s.store.Put(path.Join(s.path, addr), []byte(addr), opts)
 }
 
-func convertToStringArray(entries []store.KVEntry) (addrs []string) {
-	for _, entry := range entries {
-		addrs = append(addrs, string(entry.Value()))
-	}
-	return addrs
+// Store returns the underlying store used by KV discovery.
+func (s *Discovery) Store() store.Store {
+	return s.store
 }

+ 80 - 6
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/kv/kv_test.go

@@ -1,20 +1,94 @@
 package kv
 
 import (
+	"errors"
+	"path"
 	"testing"
+	"time"
 
+	"github.com/docker/swarm/discovery"
+	"github.com/docker/swarm/pkg/store"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 )
 
 func TestInitialize(t *testing.T) {
-	discoveryService := &Discovery{}
+	d := &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1", 0, 0))
+	s := d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 1)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1")
+	assert.Equal(t, d.path, discoveryPath)
 
-	assert.Equal(t, discoveryService.Initialize("127.0.0.1", 0).Error(), "invalid format \"127.0.0.1\", missing <path>")
+	d = &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234/path", 0, 0))
+	s = d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 1)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
+	assert.Equal(t, d.path, "path/"+discoveryPath)
 
-	assert.Error(t, discoveryService.Initialize("127.0.0.1/path", 0))
-	assert.Equal(t, discoveryService.prefix, "path")
+	d = &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0))
+	s = d.store.(*store.Mock)
+	assert.Len(t, s.Endpoints, 3)
+	assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
+	assert.Equal(t, s.Endpoints[1], "127.0.0.2:1234")
+	assert.Equal(t, s.Endpoints[2], "127.0.0.3:1234")
+	assert.Equal(t, d.path, "path/"+discoveryPath)
+}
+
+func TestWatch(t *testing.T) {
+	d := &Discovery{backend: store.MOCK}
+	assert.NoError(t, d.Initialize("127.0.0.1:1234/path", 0, 0))
+	s := d.store.(*store.Mock)
+
+	mockCh := make(chan []*store.KVPair)
+
+	// The first watch will fail.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, errors.New("test error")).Once()
+	// The second one will succeed.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil).Once()
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+	kvs := []*store.KVPair{
+		{Key: path.Join("path", discoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")},
+		{Key: path.Join("path", discoveryPath, "2.2.2.2"), Value: []byte("2.2.2.2:2222")},
+	}
+
+	stopCh := make(chan struct{})
+	ch, errCh := d.Watch(stopCh)
+
+	// It should fire an error since the first WatchRange call failed.
+	assert.EqualError(t, <-errCh, "test error")
+	// We have to drain the error channel otherwise Watch will get stuck.
+	go func() {
+		for _ = range errCh {
+		}
+	}()
+
+	// Push the entries into the store channel and make sure discovery emits.
+	mockCh <- kvs
+	assert.Equal(t, <-ch, expected)
+
+	// Add a new entry.
+	expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"})
+	kvs = append(kvs, &store.KVPair{Key: path.Join("path", discoveryPath, "3.3.3.3"), Value: []byte("3.3.3.3:3333")})
+	mockCh <- kvs
+	assert.Equal(t, <-ch, expected)
+
+	// Make sure that if an error occurs it retries.
+	// This third call to WatchTree will be checked later by AssertExpectations.
+	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil)
+	close(mockCh)
+	// Give it enough time to call WatchTree.
+	time.Sleep(3)
 
-	assert.Error(t, discoveryService.Initialize("127.0.0.1,127.0.0.2,127.0.0.3/path", 0))
-	assert.Equal(t, discoveryService.prefix, "path")
+	// Stop and make sure it closes all channels.
+	close(stopCh)
+	assert.Nil(t, <-ch)
+	assert.Nil(t, <-errCh)
 
+	s.AssertExpectations(t)
 }

+ 16 - 8
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes.go

@@ -2,21 +2,27 @@ package nodes
 
 import (
 	"strings"
+	"time"
 
 	"github.com/docker/swarm/discovery"
 )
 
 // Discovery is exported
 type Discovery struct {
-	entries []*discovery.Entry
+	entries discovery.Entries
 }
 
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("nodes", &Discovery{})
 }
 
 // Initialize is exported
-func (s *Discovery) Initialize(uris string, _ uint64) error {
+func (s *Discovery) Initialize(uris string, _ time.Duration, _ time.Duration) error {
 	for _, input := range strings.Split(uris, ",") {
 		for _, ip := range discovery.Generate(input) {
 			entry, err := discovery.NewEntry(ip)
@@ -30,13 +36,15 @@ func (s *Discovery) Initialize(uris string, _ uint64) error {
 	return nil
 }
 
-// Fetch is exported
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-	return s.entries, nil
-}
-
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	go func() {
+		defer close(ch)
+		ch <- s.entries
+		<-stopCh
+	}()
+	return ch, nil
 }
 
 // Register is exported

+ 29 - 17
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/nodes/nodes_test.go

@@ -3,29 +3,41 @@ package nodes
 import (
 	"testing"
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestInitialise(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0)
-	assert.Equal(t, len(discovery.entries), 2)
-	assert.Equal(t, discovery.entries[0].String(), "1.1.1.1:1111")
-	assert.Equal(t, discovery.entries[1].String(), "2.2.2.2:2222")
+func TestInitialize(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
+	assert.Equal(t, len(d.entries), 2)
+	assert.Equal(t, d.entries[0].String(), "1.1.1.1:1111")
+	assert.Equal(t, d.entries[1].String(), "2.2.2.2:2222")
 }
 
-func TestInitialiseWithPattern(t *testing.T) {
-	discovery := &Discovery{}
-	discovery.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0)
-	assert.Equal(t, len(discovery.entries), 5)
-	assert.Equal(t, discovery.entries[0].String(), "1.1.1.1:1111")
-	assert.Equal(t, discovery.entries[1].String(), "1.1.1.2:1111")
-	assert.Equal(t, discovery.entries[2].String(), "2.2.2.2:2222")
-	assert.Equal(t, discovery.entries[3].String(), "2.2.2.3:2222")
-	assert.Equal(t, discovery.entries[4].String(), "2.2.2.4:2222")
+func TestInitializeWithPattern(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0)
+	assert.Equal(t, len(d.entries), 5)
+	assert.Equal(t, d.entries[0].String(), "1.1.1.1:1111")
+	assert.Equal(t, d.entries[1].String(), "1.1.1.2:1111")
+	assert.Equal(t, d.entries[2].String(), "2.2.2.2:2222")
+	assert.Equal(t, d.entries[3].String(), "2.2.2.3:2222")
+	assert.Equal(t, d.entries[4].String(), "2.2.2.4:2222")
+}
+
+func TestWatch(t *testing.T) {
+	d := &Discovery{}
+	d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
+	expected := discovery.Entries{
+		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
+		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
+	}
+	ch, _ := d.Watch(nil)
+	assert.True(t, expected.Equals(<-ch))
 }
 
 func TestRegister(t *testing.T) {
-	discovery := &Discovery{}
-	assert.Error(t, discovery.Register("0.0.0.0"))
+	d := &Discovery{}
+	assert.Error(t, d.Register("0.0.0.0"))
 }

+ 50 - 11
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token.go

@@ -17,17 +17,23 @@ const DiscoveryURL = "https://discovery-stage.hub.docker.com/v1"
 
 // Discovery is exported
 type Discovery struct {
-	heartbeat uint64
+	heartbeat time.Duration
+	ttl       time.Duration
 	url       string
 	token     string
 }
 
 func init() {
+	Init()
+}
+
+// Init is exported
+func Init() {
 	discovery.Register("token", &Discovery{})
 }
 
 // Initialize is exported
-func (s *Discovery) Initialize(urltoken string, heartbeat uint64) error {
+func (s *Discovery) Initialize(urltoken string, heartbeat time.Duration, ttl time.Duration) error {
 	if i := strings.LastIndex(urltoken, "/"); i != -1 {
 		s.url = "https://" + urltoken[:i]
 		s.token = urltoken[i+1:]
@@ -40,13 +46,13 @@ func (s *Discovery) Initialize(urltoken string, heartbeat uint64) error {
 		return errors.New("token is empty")
 	}
 	s.heartbeat = heartbeat
+	s.ttl = ttl
 
 	return nil
 }
 
 // Fetch returns the list of entries for the discovery service at the specified endpoint
-func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
-
+func (s *Discovery) fetch() (discovery.Entries, error) {
 	resp, err := http.Get(fmt.Sprintf("%s/%s/%s", s.url, "clusters", s.token))
 	if err != nil {
 		return nil, err
@@ -57,7 +63,7 @@ func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
 	var addrs []string
 	if resp.StatusCode == http.StatusOK {
 		if err := json.NewDecoder(resp.Body).Decode(&addrs); err != nil {
-			return nil, err
+			return nil, fmt.Errorf("Failed to decode response: %v", err)
 		}
 	} else {
 		return nil, fmt.Errorf("Failed to fetch entries, Discovery service returned %d HTTP status code", resp.StatusCode)
@@ -67,13 +73,46 @@ func (s *Discovery) Fetch() ([]*discovery.Entry, error) {
 }
 
 // Watch is exported
-func (s *Discovery) Watch(callback discovery.WatchCallback) {
-	for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
-		entries, err := s.Fetch()
-		if err == nil {
-			callback(entries)
+func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
+	ch := make(chan discovery.Entries)
+	ticker := time.NewTicker(s.heartbeat)
+	errCh := make(chan error)
+
+	go func() {
+		defer close(ch)
+		defer close(errCh)
+
+		// Send the initial entries if available.
+		currentEntries, err := s.fetch()
+		if err != nil {
+			errCh <- err
+		} else {
+			ch <- currentEntries
 		}
-	}
+
+		// Periodically send updates.
+		for {
+			select {
+			case <-ticker.C:
+				newEntries, err := s.fetch()
+				if err != nil {
+					errCh <- err
+					continue
+				}
+
+				// Check if the file has really changed.
+				if !newEntries.Equals(currentEntries) {
+					ch <- newEntries
+				}
+				currentEntries = newEntries
+			case <-stopCh:
+				ticker.Stop()
+				return
+			}
+		}
+	}()
+
+	return ch, nil
 }
 
 // Register adds a new entry identified by the into the discovery service

+ 22 - 10
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/discovery/token/token_test.go

@@ -2,35 +2,47 @@ package token
 
 import (
 	"testing"
+	"time"
 
+	"github.com/docker/swarm/discovery"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestInitialize(t *testing.T) {
 	discovery := &Discovery{}
-	err := discovery.Initialize("token", 0)
+	err := discovery.Initialize("token", 0, 0)
 	assert.NoError(t, err)
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.url, DiscoveryURL)
 
-	err = discovery.Initialize("custom/path/token", 0)
+	err = discovery.Initialize("custom/path/token", 0, 0)
 	assert.NoError(t, err)
 	assert.Equal(t, discovery.token, "token")
 	assert.Equal(t, discovery.url, "https://custom/path")
 
-	err = discovery.Initialize("", 0)
+	err = discovery.Initialize("", 0, 0)
 	assert.Error(t, err)
 }
 
 func TestRegister(t *testing.T) {
-	discovery := &Discovery{token: "TEST_TOKEN", url: DiscoveryURL}
+	d := &Discovery{token: "TEST_TOKEN", url: DiscoveryURL, heartbeat: 1}
 	expected := "127.0.0.1:2675"
-	assert.NoError(t, discovery.Register(expected))
-
-	addrs, err := discovery.Fetch()
+	expectedEntries, err := discovery.CreateEntries([]string{expected})
 	assert.NoError(t, err)
-	assert.Equal(t, len(addrs), 1)
-	assert.Equal(t, addrs[0].String(), expected)
 
-	assert.NoError(t, discovery.Register(expected))
+	// Register
+	assert.NoError(t, d.Register(expected))
+
+	// Watch
+	ch, errCh := d.Watch(nil)
+	select {
+	case entries := <-ch:
+		assert.True(t, entries.Equals(expectedEntries))
+	case err := <-errCh:
+		t.Fatal(err)
+	case <-time.After(5 * time.Second):
+		t.Fatal("Timed out")
+	}
+
+	assert.NoError(t, d.Register(expected))
 }

+ 25 - 21
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/README.md

@@ -1,6 +1,10 @@
 # Storage
 
-This package is used by the discovery service to register machines inside the cluster. It is also used to store cluster's metadata.
+The goal of `pkg/store` is to abstract common store operations for multiple Key/Value backends.
+
+For example, you can use it to store your metadata or for service discovery to register machines and endpoints inside your cluster.
+
+As of now, `pkg/store` offers support for `Consul`, `Etcd` and `Zookeeper`.
 
 ## Example of usage
 
@@ -19,15 +23,16 @@ import (
 
 func main() {
 	var (
+		// Consul local address
 		client = "localhost:8500"
 	)
 
 	// Initialize a new store with consul
-	kv, err := store.CreateStore(
-		store.Consul,
+	kv, err = store.NewStore(
+		store.CONSUL, // or "consul"
 		[]string{client},
-		store.Config{
-		    Timeout: 10*time.Second
+		&store.Config{
+			Timeout: 10*time.Second,
 		},
 	)
 	if err != nil {
@@ -35,17 +40,17 @@ func main() {
 	}
 
 	key := "foo"
-	err = kv.Put(key, []byte("bar"))
+	err = kv.Put(key, []byte("bar"), nil)
 	if err != nil {
 		log.Error("Error trying to put value at key `", key, "`")
 	}
 
-	value, _, err := kv.Get(key)
+	pair, err := kv.Get(key)
 	if err != nil {
 		log.Error("Error trying accessing value at key `", key, "`")
 	}
 
-	log.Info("value: ", string(value))
+	log.Info("value: ", string(pair.Value))
 }
 ```
 
@@ -57,23 +62,22 @@ A new **storage backend** should include those calls:
 
 ```go
 type Store interface {
-	Put(key string, value []byte) error
-	Get(key string) (value []byte, lastIndex uint64, err error)
+	Put(key string, value []byte, options *WriteOptions) error
+	Get(key string) (*KVPair, error)
 	Delete(key string) error
 	Exists(key string) (bool, error)
-	Watch(key string, ttl uint64, callback WatchCallback) error
-	CancelWatch(key string) error
-	Acquire(key string, value []byte) (string, error)
-	Release(session string) error
-	GetRange(prefix string) (value [][]byte, err error)
-	DeleteRange(prefix string) error
-	WatchRange(prefix string, filter string, heartbeat uint64, callback WatchCallback) error
-	CancelWatchRange(prefix string) error
-	AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error)
-	AtomicDelete(key string, oldValue []byte, index uint64) (bool, error)
+	Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error)
+	WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error)
+	NewLock(key string, options *LockOptions) (Locker, error)
+	List(prefix string) ([]*KVPair, error)
+	DeleteTree(prefix string) error
+	AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
+	AtomicDelete(key string, previous *KVPair) (bool, error)
 }
 ```
 
-To be elligible as a **discovery backend** only, a K/V store implementation should at least offer `Get`, `Put`, `WatchRange`, `GetRange`.
+In the case of Swarm and to be eligible as a **discovery backend** only, a K/V store implementation should at least offer `Get`, `Put`, `WatchTree` and `List`.
+
+`Put` should support usage of `ttl` to be able to remove entries in case of a node failure.
 
 You can get inspiration from existing backends to create a new one. This interface could be subject to changes to improve the experience of using the library and contributing to a new backend.

+ 264 - 162
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul.go

@@ -2,40 +2,39 @@ package store
 
 import (
 	"crypto/tls"
-	"errors"
 	"net/http"
+	"strings"
+	"sync"
 	"time"
 
 	log "github.com/Sirupsen/logrus"
 	api "github.com/hashicorp/consul/api"
 )
 
-var (
-	// ErrSessionUndefined is exported
-	ErrSessionUndefined = errors.New("Session does not exist")
+const (
+	// DefaultWatchWaitTime is how long we block for at a time to check if the
+	// watched key has changed.  This affects the minimum time it takes to
+	// cancel a watch.
+	DefaultWatchWaitTime = 15 * time.Second
 )
 
-// Consul embeds the client and watches/lock sessions
+// Consul embeds the client and watches
 type Consul struct {
-	config   *api.Config
-	client   *api.Client
-	sessions map[string]*api.Session
-	watches  map[string]*Watch
+	sync.Mutex
+	config           *api.Config
+	client           *api.Client
+	ephemeralTTL     time.Duration
+	ephemeralSession string
 }
 
-// Watch embeds the event channel and the
-// refresh interval
-type Watch struct {
-	LastIndex uint64
-	Interval  time.Duration
+type consulLock struct {
+	lock *api.Lock
 }
 
 // InitializeConsul creates a new Consul client given
 // a list of endpoints and optional tls config
-func InitializeConsul(endpoints []string, options Config) (Store, error) {
+func InitializeConsul(endpoints []string, options *Config) (Store, error) {
 	s := &Consul{}
-	s.sessions = make(map[string]*api.Session)
-	s.watches = make(map[string]*Watch)
 
 	// Create Consul client
 	config := api.DefaultConfig()
@@ -44,12 +43,17 @@ func InitializeConsul(endpoints []string, options Config) (Store, error) {
 	config.Address = endpoints[0]
 	config.Scheme = "http"
 
-	if options.TLS != nil {
-		s.setTLS(options.TLS)
-	}
-
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.TLS != nil {
+			s.setTLS(options.TLS)
+		}
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
+		if options.EphemeralTTL != 0 {
+			s.setEphemeralTTL(options.EphemeralTTL)
+		}
 	}
 
 	// Creates a new client
@@ -76,222 +80,315 @@ func (s *Consul) setTimeout(time time.Duration) {
 	s.config.WaitTime = time
 }
 
+// SetEphemeralTTL sets the ttl for ephemeral nodes
+func (s *Consul) setEphemeralTTL(ttl time.Duration) {
+	s.ephemeralTTL = ttl
+}
+
+// createEphemeralSession creates the global session
+// once that is used to delete keys at node failure
+func (s *Consul) createEphemeralSession() error {
+	s.Lock()
+	defer s.Unlock()
+
+	// Create new session
+	if s.ephemeralSession == "" {
+		entry := &api.SessionEntry{
+			Behavior: api.SessionBehaviorDelete,
+			TTL:      s.ephemeralTTL.String(),
+		}
+		// Create global ephemeral keys session
+		session, _, err := s.client.Session().Create(entry, nil)
+		if err != nil {
+			return err
+		}
+		s.ephemeralSession = session
+	}
+	return nil
+}
+
+// checkActiveSession checks if the key already has a session attached
+func (s *Consul) checkActiveSession(key string) (string, error) {
+	pair, _, err := s.client.KV().Get(key, nil)
+	if err != nil {
+		return "", err
+	}
+	if pair != nil && pair.Session != "" {
+		return pair.Session, nil
+	}
+	return "", nil
+}
+
+// Normalize the key for usage in Consul
+func (s *Consul) normalize(key string) string {
+	key = normalize(key)
+	return strings.TrimPrefix(key, "/")
+}
+
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
-func (s *Consul) Get(key string) (value []byte, lastIndex uint64, err error) {
-	pair, meta, err := s.client.KV().Get(partialFormat(key), nil)
+func (s *Consul) Get(key string) (*KVPair, error) {
+	options := &api.QueryOptions{
+		AllowStale:        false,
+		RequireConsistent: true,
+	}
+	pair, meta, err := s.client.KV().Get(s.normalize(key), options)
 	if err != nil {
-		return nil, 0, err
+		return nil, err
 	}
 	if pair == nil {
-		return nil, 0, ErrKeyNotFound
+		return nil, ErrKeyNotFound
 	}
-	return pair.Value, meta.LastIndex, nil
+	return &KVPair{pair.Key, pair.Value, meta.LastIndex}, nil
 }
 
 // Put a value at "key"
-func (s *Consul) Put(key string, value []byte) error {
-	p := &api.KVPair{Key: partialFormat(key), Value: value}
-	if s.client == nil {
-		log.Error("Error initializing client")
+func (s *Consul) Put(key string, value []byte, opts *WriteOptions) error {
+
+	key = s.normalize(key)
+
+	p := &api.KVPair{
+		Key:   key,
+		Value: value,
 	}
+
+	if opts != nil && opts.Ephemeral {
+		// Check if there is any previous session with an active TTL
+		previous, err := s.checkActiveSession(key)
+		if err != nil {
+			return err
+		}
+
+		// Create the global ephemeral session if it does not exist yet
+		if s.ephemeralSession == "" {
+			if err = s.createEphemeralSession(); err != nil {
+				return err
+			}
+		}
+
+		// If a previous session is still active for that key, use it
+		// else we use the global ephemeral session
+		if previous != "" {
+			p.Session = previous
+		} else {
+			p.Session = s.ephemeralSession
+		}
+
+		// Create lock option with the
+		// EphemeralSession
+		lockOpts := &api.LockOptions{
+			Key:     key,
+			Session: p.Session,
+		}
+
+		// Lock and ignore if lock is held
+		// It's just a placeholder for the
+		// ephemeral behavior
+		lock, _ := s.client.LockOpts(lockOpts)
+		if lock != nil {
+			lock.Lock(nil)
+		}
+
+		// Renew the session
+		_, _, err = s.client.Session().Renew(p.Session, nil)
+		if err != nil {
+			s.ephemeralSession = ""
+			return err
+		}
+	}
+
 	_, err := s.client.KV().Put(p, nil)
 	return err
 }
 
 // Delete a value at "key"
 func (s *Consul) Delete(key string) error {
-	_, err := s.client.KV().Delete(partialFormat(key), nil)
+	_, err := s.client.KV().Delete(s.normalize(key), nil)
 	return err
 }
 
 // Exists checks that the key exists inside the store
 func (s *Consul) Exists(key string) (bool, error) {
-	_, _, err := s.Get(key)
+	_, err := s.Get(key)
 	if err != nil && err == ErrKeyNotFound {
 		return false, err
 	}
 	return true, nil
 }
 
-// GetRange gets a range of values at "directory"
-func (s *Consul) GetRange(prefix string) (kvi []KVEntry, err error) {
-	pairs, _, err := s.client.KV().List(partialFormat(prefix), nil)
+// List the content of a given prefix
+func (s *Consul) List(prefix string) ([]*KVPair, error) {
+	pairs, _, err := s.client.KV().List(s.normalize(prefix), nil)
 	if err != nil {
 		return nil, err
 	}
 	if len(pairs) == 0 {
 		return nil, ErrKeyNotFound
 	}
+	kv := []*KVPair{}
 	for _, pair := range pairs {
 		if pair.Key == prefix {
 			continue
 		}
-		kvi = append(kvi, &kviTuple{pair.Key, pair.Value, pair.ModifyIndex})
+		kv = append(kv, &KVPair{pair.Key, pair.Value, pair.ModifyIndex})
 	}
-	return kvi, nil
+	return kv, nil
 }
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Consul) DeleteRange(prefix string) error {
-	_, err := s.client.KV().DeleteTree(partialFormat(prefix), nil)
+// DeleteTree deletes a range of keys based on prefix
+func (s *Consul) DeleteTree(prefix string) error {
+	_, err := s.client.KV().DeleteTree(s.normalize(prefix), nil)
 	return err
 }
 
-// Watch a single key for modifications
-func (s *Consul) Watch(key string, heartbeat time.Duration, callback WatchCallback) error {
-	fkey := partialFormat(key)
-
-	// We get the last index first
-	_, meta, err := s.client.KV().Get(fkey, nil)
-	if err != nil {
-		return err
-	}
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Consul) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	key = s.normalize(key)
+	kv := s.client.KV()
+	watchCh := make(chan *KVPair)
 
-	// Add watch to map
-	s.watches[fkey] = &Watch{LastIndex: meta.LastIndex, Interval: heartbeat}
-	eventChan := s.waitForChange(fkey)
+	go func() {
+		defer close(watchCh)
 
-	for _ = range eventChan {
-		log.WithField("name", "consul").Debug("Key watch triggered")
-		entry, index, err := s.Get(key)
-		if err != nil {
-			log.Error("Cannot refresh the key: ", fkey, ", cancelling watch")
-			s.watches[fkey] = nil
-			return err
+		// Use a wait time in order to check if we should quit from time to
+		// time.
+		opts := &api.QueryOptions{WaitTime: DefaultWatchWaitTime}
+		for {
+			// Check if we should quit
+			select {
+			case <-stopCh:
+				return
+			default:
+			}
+			pair, meta, err := kv.Get(key, opts)
+			if err != nil {
+				log.Errorf("consul: %v", err)
+				return
+			}
+			// If LastIndex didn't change then it means `Get` returned because
+			// of the WaitTime and the key didn't change.
+			if opts.WaitIndex == meta.LastIndex {
+				continue
+			}
+			opts.WaitIndex = meta.LastIndex
+			// FIXME: What happens when a key is deleted?
+			if pair != nil {
+				watchCh <- &KVPair{pair.Key, pair.Value, pair.ModifyIndex}
+			}
 		}
+	}()
 
-		value := []KVEntry{&kviTuple{key, entry, index}}
-		callback(value)
-	}
-
-	return nil
+	return watchCh, nil
 }
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Consul) CancelWatch(key string) error {
-	key = partialFormat(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
-	}
-	s.watches[key] = nil
-	return nil
-}
-
-// Internal function to check if a key has changed
-func (s *Consul) waitForChange(key string) <-chan uint64 {
-	ch := make(chan uint64)
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Consul) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	prefix = s.normalize(prefix)
 	kv := s.client.KV()
+	watchCh := make(chan []*KVPair)
+
 	go func() {
+		defer close(watchCh)
+
+		// Use a wait time in order to check if we should quit from time to
+		// time.
+		opts := &api.QueryOptions{WaitTime: DefaultWatchWaitTime}
 		for {
-			watch, ok := s.watches[key]
-			if !ok {
-				log.Error("Cannot access last index for key: ", key, " closing channel")
-				break
-			}
-			option := &api.QueryOptions{
-				WaitIndex: watch.LastIndex,
-				WaitTime:  watch.Interval,
+			// Check if we should quit
+			select {
+			case <-stopCh:
+				return
+			default:
 			}
-			_, meta, err := kv.List(key, option)
+
+			pairs, meta, err := kv.List(prefix, opts)
 			if err != nil {
-				log.WithField("name", "consul").Errorf("Discovery error: %v", err)
-				break
+				log.Errorf("consul: %v", err)
+				return
+			}
+			// If LastIndex didn't change then it means `Get` returned because
+			// of the WaitTime and the key didn't change.
+			if opts.WaitIndex == meta.LastIndex {
+				continue
 			}
-			watch.LastIndex = meta.LastIndex
-			ch <- watch.LastIndex
+			opts.WaitIndex = meta.LastIndex
+			kv := []*KVPair{}
+			for _, pair := range pairs {
+				if pair.Key == prefix {
+					continue
+				}
+				kv = append(kv, &KVPair{pair.Key, pair.Value, pair.ModifyIndex})
+			}
+			watchCh <- kv
 		}
-		close(ch)
 	}()
-	return ch
-}
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Consul) WatchRange(prefix string, filter string, heartbeat time.Duration, callback WatchCallback) error {
-	fprefix := partialFormat(prefix)
+	return watchCh, nil
+}
 
-	// We get the last index first
-	_, meta, err := s.client.KV().Get(prefix, nil)
-	if err != nil {
-		return err
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Consul) NewLock(key string, options *LockOptions) (Locker, error) {
+	consulOpts := &api.LockOptions{
+		Key: s.normalize(key),
 	}
-
-	// Add watch to map
-	s.watches[fprefix] = &Watch{LastIndex: meta.LastIndex, Interval: heartbeat}
-	eventChan := s.waitForChange(fprefix)
-
-	for _ = range eventChan {
-		log.WithField("name", "consul").Debug("Key watch triggered")
-		kvi, err := s.GetRange(prefix)
-		if err != nil {
-			log.Error("Cannot refresh keys with prefix: ", fprefix, ", cancelling watch")
-			s.watches[fprefix] = nil
-			return err
-		}
-		callback(kvi)
+	if options != nil {
+		consulOpts.Value = options.Value
 	}
-
-	return nil
-}
-
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Consul) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(prefix)
-}
-
-// Acquire the lock for "key"/"directory"
-func (s *Consul) Acquire(key string, value []byte) (string, error) {
-	key = partialFormat(key)
-	session := s.client.Session()
-	id, _, err := session.CreateNoChecks(nil, nil)
+	l, err := s.client.LockOpts(consulOpts)
 	if err != nil {
-		return "", err
-	}
-
-	// Add session to map
-	s.sessions[id] = session
-
-	p := &api.KVPair{Key: key, Value: value, Session: id}
-	if work, _, err := s.client.KV().Acquire(p, nil); err != nil {
-		return "", err
-	} else if !work {
-		return "", ErrCannotLock
+		return nil, err
 	}
+	return &consulLock{lock: l}, nil
+}
 
-	return id, nil
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *consulLock) Lock() (<-chan struct{}, error) {
+	return l.lock.Lock(nil)
 }
 
-// Release the lock for "key"/"directory"
-func (s *Consul) Release(id string) error {
-	if _, ok := s.sessions[id]; !ok {
-		log.Error("Lock session does not exist")
-		return ErrSessionUndefined
-	}
-	session := s.sessions[id]
-	session.Destroy(id, nil)
-	s.sessions[id] = nil
-	return nil
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *consulLock) Unlock() error {
+	return l.lock.Unlock()
 }
 
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
-func (s *Consul) AtomicPut(key string, _ []byte, newValue []byte, index uint64) (bool, error) {
-	p := &api.KVPair{Key: partialFormat(key), Value: newValue, ModifyIndex: index}
+func (s *Consul) AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
+	}
+
+	p := &api.KVPair{Key: s.normalize(key), Value: value, ModifyIndex: previous.LastIndex}
 	if work, _, err := s.client.KV().CAS(p, nil); err != nil {
-		return false, err
+		return false, nil, err
 	} else if !work {
-		return false, ErrKeyModified
+		return false, nil, ErrKeyModified
 	}
-	return true, nil
+
+	pair, err := s.Get(key)
+	if err != nil {
+		return false, nil, err
+	}
+	return true, pair, nil
 }
 
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
-func (s *Consul) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	p := &api.KVPair{Key: partialFormat(key), ModifyIndex: index}
+func (s *Consul) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
+
+	p := &api.KVPair{Key: s.normalize(key), ModifyIndex: previous.LastIndex}
 	if work, _, err := s.client.KV().DeleteCAS(p, nil); err != nil {
 		return false, err
 	} else if !work {
@@ -299,3 +396,8 @@ func (s *Consul) AtomicDelete(key string, oldValue []byte, index uint64) (bool,
 	}
 	return true, nil
 }
+
+// Close closes the client connection
+func (s *Consul) Close() {
+	return
+}

+ 69 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/consul_test.go

@@ -0,0 +1,69 @@
+package store
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func makeConsulClient(t *testing.T) Store {
+	client := "localhost:8500"
+
+	kv, err := NewStore(
+		CONSUL,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestConsulStore(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	testStore(t, kv)
+}
+
+func TestCreateEphemeralSession(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	consul := kv.(*Consul)
+
+	err := consul.createEphemeralSession()
+	assert.NoError(t, err)
+	assert.NotEqual(t, consul.ephemeralSession, "")
+}
+
+func TestCheckActiveSession(t *testing.T) {
+	kv := makeConsulClient(t)
+
+	consul := kv.(*Consul)
+
+	key := "foo"
+	value := []byte("bar")
+
+	// Put the first key with the Ephemeral flag
+	err := kv.Put(key, value, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Session should not be empty
+	session, err := consul.checkActiveSession(key)
+	assert.NoError(t, err)
+	assert.NotEqual(t, session, "")
+
+	// Delete the key
+	err = kv.Delete(key)
+	assert.NoError(t, err)
+
+	// Check the session again, it should return nothing
+	session, err = consul.checkActiveSession(key)
+	assert.NoError(t, err)
+	assert.Equal(t, session, "")
+}

+ 288 - 108
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd.go

@@ -7,33 +7,59 @@ import (
 	"strings"
 	"time"
 
-	log "github.com/Sirupsen/logrus"
 	etcd "github.com/coreos/go-etcd/etcd"
 )
 
 // Etcd embeds the client
 type Etcd struct {
-	client  *etcd.Client
-	watches map[string]chan<- bool
+	client       *etcd.Client
+	ephemeralTTL time.Duration
 }
 
+type etcdLock struct {
+	client   *etcd.Client
+	stopLock chan struct{}
+	key      string
+	value    string
+	last     *etcd.Response
+	ttl      uint64
+}
+
+const (
+	defaultLockTTL    = 20 * time.Second
+	defaultUpdateTime = 5 * time.Second
+
+	// periodicSync is the time between each call to SyncCluster
+	periodicSync = 10 * time.Minute
+)
+
 // InitializeEtcd creates a new Etcd client given
 // a list of endpoints and optional tls config
-func InitializeEtcd(addrs []string, options Config) (Store, error) {
+func InitializeEtcd(addrs []string, options *Config) (Store, error) {
 	s := &Etcd{}
-	s.watches = make(map[string]chan<- bool)
 
 	entries := createEndpoints(addrs, "http")
 	s.client = etcd.NewClient(entries)
 
-	if options.TLS != nil {
-		s.setTLS(options.TLS)
-	}
-
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.TLS != nil {
+			s.setTLS(options.TLS)
+		}
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
+		if options.EphemeralTTL != 0 {
+			s.setEphemeralTTL(options.EphemeralTTL)
+		}
 	}
 
+	go func() {
+		for {
+			s.client.SyncCluster()
+			time.Sleep(periodicSync)
+		}
+	}()
 	return s, nil
 }
 
@@ -65,10 +91,14 @@ func (s *Etcd) setTimeout(time time.Duration) {
 	s.client.SetDialTimeout(time)
 }
 
+// SetHeartbeat sets the heartbeat value to notify we are alive
+func (s *Etcd) setEphemeralTTL(time time.Duration) {
+	s.ephemeralTTL = time
+}
+
 // Create the entire path for a directory that does not exist
 func (s *Etcd) createDirectory(path string) error {
-	// TODO Handle TTL at key/dir creation -> use K/V struct for key infos?
-	if _, err := s.client.CreateDir(format(path), 10); err != nil {
+	if _, err := s.client.CreateDir(normalize(path), 10); err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			if etcdError.ErrorCode != 105 { // Skip key already exists
 				return err
@@ -82,28 +112,35 @@ func (s *Etcd) createDirectory(path string) error {
 
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
-func (s *Etcd) Get(key string) (value []byte, lastIndex uint64, err error) {
-	result, err := s.client.Get(format(key), false, false)
+func (s *Etcd) Get(key string) (*KVPair, error) {
+	result, err := s.client.Get(normalize(key), false, false)
 	if err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			// Not a Directory or Not a file
 			if etcdError.ErrorCode == 102 || etcdError.ErrorCode == 104 {
-				return nil, 0, ErrKeyNotFound
+				return nil, ErrKeyNotFound
 			}
 		}
-		return nil, 0, err
+		return nil, err
 	}
-	return []byte(result.Node.Value), result.Node.ModifiedIndex, nil
+	return &KVPair{key, []byte(result.Node.Value), result.Node.ModifiedIndex}, nil
 }
 
 // Put a value at "key"
-func (s *Etcd) Put(key string, value []byte) error {
-	if _, err := s.client.Set(key, string(value), 0); err != nil {
+func (s *Etcd) Put(key string, value []byte, opts *WriteOptions) error {
+
+	// Default TTL = 0 means no expiration
+	var ttl uint64
+	if opts != nil && opts.Ephemeral {
+		ttl = uint64(s.ephemeralTTL.Seconds())
+	}
+
+	if _, err := s.client.Set(key, string(value), ttl); err != nil {
 		if etcdError, ok := err.(*etcd.EtcdError); ok {
 			if etcdError.ErrorCode == 104 { // Not a directory
 				// Remove the last element (the actual key) and set the prefix as a dir
-				err = s.createDirectory(getDir(key))
-				if _, err := s.client.Set(key, string(value), 0); err != nil {
+				err = s.createDirectory(getDirectory(key))
+				if _, err := s.client.Set(key, string(value), ttl); err != nil {
 					return err
 				}
 			}
@@ -115,7 +152,7 @@ func (s *Etcd) Put(key string, value []byte) error {
 
 // Delete a value at "key"
 func (s *Etcd) Delete(key string) error {
-	if _, err := s.client.Delete(format(key), false); err != nil {
+	if _, err := s.client.Delete(normalize(key), false); err != nil {
 		return err
 	}
 	return nil
@@ -123,9 +160,9 @@ func (s *Etcd) Delete(key string) error {
 
 // Exists checks if the key exists inside the store
 func (s *Etcd) Exists(key string) (bool, error) {
-	value, _, err := s.Get(key)
+	entry, err := s.Get(key)
 	if err != nil {
-		if err == ErrKeyNotFound || value == nil {
+		if err == ErrKeyNotFound || entry.Value == nil {
 			return false, nil
 		}
 		return false, err
@@ -133,132 +170,275 @@ func (s *Etcd) Exists(key string) (bool, error) {
 	return true, nil
 }
 
-// Watch a single key for modifications
-func (s *Etcd) Watch(key string, _ time.Duration, callback WatchCallback) error {
-	key = format(key)
-	watchChan := make(chan *etcd.Response)
-	stopChan := make(chan bool)
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Etcd) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	// Get the current value
+	current, err := s.Get(key)
+	if err != nil {
+		return nil, err
+	}
 
-	// Create new Watch entry
-	s.watches[key] = stopChan
+	// Start an etcd watch.
+	// Note: etcd will send the current value through the channel.
+	etcdWatchCh := make(chan *etcd.Response)
+	etcdStopCh := make(chan bool)
+	go s.client.Watch(normalize(key), 0, false, etcdWatchCh, etcdStopCh)
 
-	// Start watch
-	go s.client.Watch(key, 0, false, watchChan, stopChan)
+	// Adapter goroutine: The goal here is to convert wathever format etcd is
+	// using into our interface.
+	watchCh := make(chan *KVPair)
+	go func() {
+		defer close(watchCh)
 
-	for _ = range watchChan {
-		log.WithField("name", "etcd").Debug("Discovery watch triggered")
-		entry, index, err := s.Get(key)
-		if err != nil {
-			log.Error("Cannot refresh the key: ", key, ", cancelling watch")
-			s.watches[key] = nil
-			return err
+		// Push the current value through the channel.
+		watchCh <- current
+
+		for {
+			select {
+			case result := <-etcdWatchCh:
+				watchCh <- &KVPair{
+					key,
+					[]byte(result.Node.Value),
+					result.Node.ModifiedIndex,
+				}
+			case <-stopCh:
+				etcdStopCh <- true
+				return
+			}
 		}
-		kvi := []KVEntry{&kviTuple{key, entry, index}}
-		callback(kvi)
-	}
-	return nil
+	}()
+	return watchCh, nil
 }
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Etcd) CancelWatch(key string) error {
-	key = format(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Etcd) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	// Get the current value
+	current, err := s.List(prefix)
+	if err != nil {
+		return nil, err
 	}
-	// Send stop signal to event chan
-	s.watches[key] <- true
-	s.watches[key] = nil
-	return nil
+
+	// Start an etcd watch.
+	etcdWatchCh := make(chan *etcd.Response)
+	etcdStopCh := make(chan bool)
+	go s.client.Watch(normalize(prefix), 0, true, etcdWatchCh, etcdStopCh)
+
+	// Adapter goroutine: The goal here is to convert wathever format etcd is
+	// using into our interface.
+	watchCh := make(chan []*KVPair)
+	go func() {
+		defer close(watchCh)
+
+		// Push the current value through the channel.
+		watchCh <- current
+
+		for {
+			select {
+			case <-etcdWatchCh:
+				// FIXME: We should probably use the value pushed by the channel.
+				// However, .Node.Nodes seems to be empty.
+				if list, err := s.List(prefix); err == nil {
+					watchCh <- list
+				}
+			case <-stopCh:
+				etcdStopCh <- true
+				return
+			}
+		}
+	}()
+	return watchCh, nil
 }
 
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
-func (s *Etcd) AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error) {
-	resp, err := s.client.CompareAndSwap(format(key), string(newValue), 5, string(oldValue), 0)
-	if err != nil {
-		return false, err
-	}
-	if !(resp.Node.Value == string(newValue) && resp.Node.Key == key && resp.Node.TTL == 5) {
-		return false, ErrKeyModified
+func (s *Etcd) AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
 	}
-	if !(resp.PrevNode.Value == string(newValue) && resp.PrevNode.Key == key && resp.PrevNode.TTL == 5) {
-		return false, ErrKeyModified
+
+	meta, err := s.client.CompareAndSwap(normalize(key), string(value), 0, "", previous.LastIndex)
+	if err != nil {
+		if etcdError, ok := err.(*etcd.EtcdError); ok {
+			if etcdError.ErrorCode == 101 { // Compare failed
+				return false, nil, ErrKeyModified
+			}
+		}
+		return false, nil, err
 	}
-	return true, nil
+	return true, &KVPair{Key: key, Value: value, LastIndex: meta.Node.ModifiedIndex}, nil
 }
 
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
-func (s *Etcd) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	resp, err := s.client.CompareAndDelete(format(key), string(oldValue), 0)
+func (s *Etcd) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
+
+	_, err := s.client.CompareAndDelete(normalize(key), "", previous.LastIndex)
 	if err != nil {
+		if etcdError, ok := err.(*etcd.EtcdError); ok {
+			if etcdError.ErrorCode == 101 { // Compare failed
+				return false, ErrKeyModified
+			}
+		}
 		return false, err
 	}
-	if !(resp.PrevNode.Value == string(oldValue) && resp.PrevNode.Key == key && resp.PrevNode.TTL == 5) {
-		return false, ErrKeyModified
-	}
 	return true, nil
 }
 
-// GetRange gets a range of values at "directory"
-func (s *Etcd) GetRange(prefix string) ([]KVEntry, error) {
-	resp, err := s.client.Get(format(prefix), true, true)
+// List the content of a given prefix
+func (s *Etcd) List(prefix string) ([]*KVPair, error) {
+	resp, err := s.client.Get(normalize(prefix), true, true)
 	if err != nil {
 		return nil, err
 	}
-	kvi := make([]KVEntry, len(resp.Node.Nodes))
-	for i, n := range resp.Node.Nodes {
-		kvi[i] = &kviTuple{n.Key, []byte(n.Value), n.ModifiedIndex}
+	kv := []*KVPair{}
+	for _, n := range resp.Node.Nodes {
+		key := strings.TrimLeft(n.Key, "/")
+		kv = append(kv, &KVPair{key, []byte(n.Value), n.ModifiedIndex})
 	}
-	return kvi, nil
+	return kv, nil
 }
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Etcd) DeleteRange(prefix string) error {
-	if _, err := s.client.Delete(format(prefix), true); err != nil {
+// DeleteTree deletes a range of keys based on prefix
+func (s *Etcd) DeleteTree(prefix string) error {
+	if _, err := s.client.Delete(normalize(prefix), true); err != nil {
 		return err
 	}
 	return nil
 }
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Etcd) WatchRange(prefix string, filter string, _ time.Duration, callback WatchCallback) error {
-	prefix = format(prefix)
-	watchChan := make(chan *etcd.Response)
-	stopChan := make(chan bool)
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Etcd) NewLock(key string, options *LockOptions) (Locker, error) {
+	var value string
+	ttl := uint64(time.Duration(defaultLockTTL).Seconds())
 
-	// Create new Watch entry
-	s.watches[prefix] = stopChan
+	// Apply options
+	if options != nil {
+		if options.Value != nil {
+			value = string(options.Value)
+		}
+		if options.TTL != 0 {
+			ttl = uint64(options.TTL.Seconds())
+		}
+	}
 
-	// Start watch
-	go s.client.Watch(prefix, 0, true, watchChan, stopChan)
-	for _ = range watchChan {
-		log.WithField("name", "etcd").Debug("Discovery watch triggered")
-		kvi, err := s.GetRange(prefix)
+	// Create lock object
+	lock := &etcdLock{
+		client: s.client,
+		key:    key,
+		value:  value,
+		ttl:    ttl,
+	}
+
+	return lock, nil
+}
+
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *etcdLock) Lock() (<-chan struct{}, error) {
+
+	key := normalize(l.key)
+
+	// Lock holder channels
+	lockHeld := make(chan struct{})
+	stopLocking := make(chan struct{})
+
+	var lastIndex uint64
+
+	for {
+		resp, err := l.client.Create(key, l.value, l.ttl)
 		if err != nil {
-			log.Error("Cannot refresh the key: ", prefix, ", cancelling watch")
-			s.watches[prefix] = nil
-			return err
+			if etcdError, ok := err.(*etcd.EtcdError); ok {
+				// Key already exists
+				if etcdError.ErrorCode != 105 {
+					lastIndex = ^uint64(0)
+				}
+			}
+		} else {
+			lastIndex = resp.Node.ModifiedIndex
+		}
+
+		_, err = l.client.CompareAndSwap(key, l.value, l.ttl, "", lastIndex)
+
+		if err == nil {
+			// Leader section
+			l.stopLock = stopLocking
+			go l.holdLock(key, lockHeld, stopLocking)
+			break
+		} else {
+			// Seeker section
+			chW := make(chan *etcd.Response)
+			chWStop := make(chan bool)
+			l.waitLock(key, chW, chWStop)
+
+			// Delete or Expire event occured
+			// Retry
+		}
+	}
+
+	return lockHeld, nil
+}
+
+// Hold the lock as long as we can
+// Updates the key ttl periodically until we receive
+// an explicit stop signal from the Unlock method
+func (l *etcdLock) holdLock(key string, lockHeld chan struct{}, stopLocking chan struct{}) {
+	defer close(lockHeld)
+
+	update := time.NewTicker(defaultUpdateTime)
+	defer update.Stop()
+
+	var err error
+
+	for {
+		select {
+		case <-update.C:
+			l.last, err = l.client.Update(key, l.value, l.ttl)
+			if err != nil {
+				return
+			}
+
+		case <-stopLocking:
+			return
 		}
-		callback(kvi)
 	}
-	return nil
 }
 
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Etcd) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(format(prefix))
+// WaitLock simply waits for the key to be available for creation
+func (l *etcdLock) waitLock(key string, eventCh chan *etcd.Response, stopWatchCh chan bool) {
+	go l.client.Watch(key, 0, false, eventCh, stopWatchCh)
+	for event := range eventCh {
+		if event.Action == "delete" || event.Action == "expire" {
+			return
+		}
+	}
 }
 
-// Acquire the lock for "key"/"directory"
-func (s *Etcd) Acquire(key string, value []byte) (string, error) {
-	return "", ErrNotImplemented
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *etcdLock) Unlock() error {
+	if l.stopLock != nil {
+		l.stopLock <- struct{}{}
+	}
+	if l.last != nil {
+		_, err := l.client.CompareAndDelete(normalize(l.key), l.value, l.last.Node.ModifiedIndex)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
 }
 
-// Release the lock for "key"/"directory"
-func (s *Etcd) Release(session string) error {
-	return ErrNotImplemented
+// Close closes the client connection
+func (s *Etcd) Close() {
+	return
 }

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/etcd_test.go

@@ -0,0 +1,30 @@
+package store
+
+import (
+	"testing"
+	"time"
+)
+
+func makeEtcdClient(t *testing.T) Store {
+	client := "localhost:4001"
+
+	kv, err := NewStore(
+		ETCD,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestEtcdStore(t *testing.T) {
+	kv := makeEtcdClient(t)
+
+	testStore(t, kv)
+}

+ 15 - 20
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/helpers.go

@@ -12,21 +12,22 @@ func createEndpoints(addrs []string, scheme string) (entries []string) {
 	return entries
 }
 
-// Formats the key
-func format(key string) string {
-	return fullpath(splitKey(key))
+// Normalize the key for each store to the form:
+//
+//     /path/to/key
+//
+func normalize(key string) string {
+	return "/" + join(splitKey(key))
 }
 
-// Formats the key partially (omits the first '/')
-func partialFormat(key string) string {
-	return partialpath(splitKey(key))
-}
-
-// Get the full directory part of the key
-func getDir(key string) string {
+// Get the full directory part of the key to the form:
+//
+//     /path/to/
+//
+func getDirectory(key string) string {
 	parts := splitKey(key)
 	parts = parts[:len(parts)-1]
-	return fullpath(parts)
+	return "/" + join(parts)
 }
 
 // SplitKey splits the key to extract path informations
@@ -39,13 +40,7 @@ func splitKey(key string) (path []string) {
 	return path
 }
 
-// Get the full correct path representation of a splitted key/directory
-func fullpath(path []string) string {
-	return "/" + strings.Join(path, "/")
-}
-
-// Get the partial correct path representation of a splitted key/directory
-// Omits the first '/'
-func partialpath(path []string) string {
-	return strings.Join(path, "/")
+// Join the path parts with '/'
+func join(parts []string) string {
+	return strings.Join(parts, "/")
 }

+ 109 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/mock.go

@@ -0,0 +1,109 @@
+package store
+
+import "github.com/stretchr/testify/mock"
+
+// Mock store. Mocks all Store functions using testify.Mock.
+type Mock struct {
+	mock.Mock
+
+	// Endpoints passed to InitializeMock
+	Endpoints []string
+	// Options passed to InitializeMock
+	Options *Config
+}
+
+// InitializeMock creates a Mock store.
+func InitializeMock(endpoints []string, options *Config) (Store, error) {
+	s := &Mock{}
+	s.Endpoints = endpoints
+	s.Options = options
+	return s, nil
+}
+
+// Put mock
+func (s *Mock) Put(key string, value []byte, opts *WriteOptions) error {
+	args := s.Mock.Called(key, value, opts)
+	return args.Error(0)
+}
+
+// Get mock
+func (s *Mock) Get(key string) (*KVPair, error) {
+	args := s.Mock.Called(key)
+	return args.Get(0).(*KVPair), args.Error(1)
+}
+
+// Delete mock
+func (s *Mock) Delete(key string) error {
+	args := s.Mock.Called(key)
+	return args.Error(0)
+}
+
+// Exists mock
+func (s *Mock) Exists(key string) (bool, error) {
+	args := s.Mock.Called(key)
+	return args.Bool(0), args.Error(1)
+}
+
+// Watch mock
+func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	args := s.Mock.Called(key, stopCh)
+	return args.Get(0).(<-chan *KVPair), args.Error(1)
+}
+
+// WatchTree mock
+func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	args := s.Mock.Called(prefix, stopCh)
+	return args.Get(0).(chan []*KVPair), args.Error(1)
+}
+
+// NewLock mock
+func (s *Mock) NewLock(key string, options *LockOptions) (Locker, error) {
+	args := s.Mock.Called(key, options)
+	return args.Get(0).(Locker), args.Error(1)
+}
+
+// List mock
+func (s *Mock) List(prefix string) ([]*KVPair, error) {
+	args := s.Mock.Called(prefix)
+	return args.Get(0).([]*KVPair), args.Error(1)
+}
+
+// DeleteTree mock
+func (s *Mock) DeleteTree(prefix string) error {
+	args := s.Mock.Called(prefix)
+	return args.Error(0)
+}
+
+// AtomicPut mock
+func (s *Mock) AtomicPut(key string, value []byte, previous *KVPair, opts *WriteOptions) (bool, *KVPair, error) {
+	args := s.Mock.Called(key, value, previous, opts)
+	return args.Bool(0), args.Get(1).(*KVPair), args.Error(2)
+}
+
+// AtomicDelete mock
+func (s *Mock) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	args := s.Mock.Called(key, previous)
+	return args.Bool(0), args.Error(1)
+}
+
+// MockLock mock implementation of Locker
+type MockLock struct {
+	mock.Mock
+}
+
+// Lock mock
+func (l *MockLock) Lock() (<-chan struct{}, error) {
+	args := l.Mock.Called()
+	return args.Get(0).(<-chan struct{}), args.Error(1)
+}
+
+// Unlock mock
+func (l *MockLock) Unlock() error {
+	args := l.Mock.Called()
+	return args.Error(0)
+}
+
+// Close mock
+func (s *Mock) Close() {
+	return
+}

+ 107 - 45
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store.go

@@ -1,17 +1,54 @@
 package store
 
 import (
+	"crypto/tls"
+	"errors"
 	"time"
 
 	log "github.com/Sirupsen/logrus"
 )
 
-// WatchCallback is used for watch methods on keys
-// and is triggered on key change
-type WatchCallback func(kviTuple []KVEntry)
+// Backend represents a KV Store Backend
+type Backend string
+
+const (
+	// MOCK backend
+	MOCK Backend = "mock"
+	// CONSUL backend
+	CONSUL = "consul"
+	// ETCD backend
+	ETCD = "etcd"
+	// ZK backend
+	ZK = "zk"
+)
 
-// Initialize creates a new Store object, initializing the client
-type Initialize func(addrs []string, options Config) (Store, error)
+var (
+	// ErrInvalidTTL is a specific error to consul
+	ErrInvalidTTL = errors.New("Invalid TTL, please change the value to the miminum allowed ttl for the chosen store")
+	// ErrNotSupported is exported
+	ErrNotSupported = errors.New("Backend storage not supported yet, please choose another one")
+	// ErrNotImplemented is exported
+	ErrNotImplemented = errors.New("Call not implemented in current backend")
+	// ErrNotReachable is exported
+	ErrNotReachable = errors.New("Api not reachable")
+	// ErrCannotLock is exported
+	ErrCannotLock = errors.New("Error acquiring the lock")
+	// ErrWatchDoesNotExist is exported
+	ErrWatchDoesNotExist = errors.New("No watch found for specified key")
+	// ErrKeyModified is exported
+	ErrKeyModified = errors.New("Unable to complete atomic operation, key modified")
+	// ErrKeyNotFound is exported
+	ErrKeyNotFound = errors.New("Key not found in store")
+	// ErrPreviousNotSpecified is exported
+	ErrPreviousNotSpecified = errors.New("Previous K/V pair should be provided for the Atomic operation")
+)
+
+// Config contains the options for a storage client
+type Config struct {
+	TLS               *tls.Config
+	ConnectionTimeout time.Duration
+	EphemeralTTL      time.Duration
+}
 
 // Store represents the backend K/V storage
 // Each store should support every call listed
@@ -19,10 +56,10 @@ type Initialize func(addrs []string, options Config) (Store, error)
 // backend for libkv
 type Store interface {
 	// Put a value at the specified key
-	Put(key string, value []byte) error
+	Put(key string, value []byte, options *WriteOptions) error
 
 	// Get a value given its key
-	Get(key string) (value []byte, lastIndex uint64, err error)
+	Get(key string) (*KVPair, error)
 
 	// Delete the value at the specified key
 	Delete(key string) error
@@ -30,61 +67,86 @@ type Store interface {
 	// Verify if a Key exists in the store
 	Exists(key string) (bool, error)
 
-	// Watch changes on a key
-	Watch(key string, heartbeat time.Duration, callback WatchCallback) error
+	// Watch changes on a key.
+	// Returns a channel that will receive changes or an error.
+	// Upon creating a watch, the current value will be sent to the channel.
+	// Providing a non-nil stopCh can be used to stop watching.
+	Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error)
 
-	// Cancel watch key
-	CancelWatch(key string) error
+	// WatchTree watches changes on a "directory"
+	// Returns a channel that will receive changes or an error.
+	// Upon creating a watch, the current value will be sent to the channel.
+	// Providing a non-nil stopCh can be used to stop watching.
+	WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error)
 
-	// Acquire the lock at key
-	Acquire(key string, value []byte) (string, error)
+	// CreateLock for a given key.
+	// The returned Locker is not held and must be acquired with `.Lock`.
+	// value is optional.
+	NewLock(key string, options *LockOptions) (Locker, error)
 
-	// Release the lock at key
-	Release(session string) error
+	// List the content of a given prefix
+	List(prefix string) ([]*KVPair, error)
 
-	// Get range of keys based on prefix
-	GetRange(prefix string) ([]KVEntry, error)
+	// DeleteTree deletes a range of keys based on prefix
+	DeleteTree(prefix string) error
 
-	// Delete range of keys based on prefix
-	DeleteRange(prefix string) error
+	// Atomic operation on a single value
+	AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
 
-	// Watch key namespaces
-	WatchRange(prefix string, filter string, heartbeat time.Duration, callback WatchCallback) error
+	// Atomic delete of a single value
+	AtomicDelete(key string, previous *KVPair) (bool, error)
 
-	// Cancel watch key range
-	CancelWatchRange(prefix string) error
+	// Close the store connection
+	Close()
+}
 
-	// Atomic operation on a single value
-	AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error)
+// KVPair represents {Key, Value, Lastindex} tuple
+type KVPair struct {
+	Key       string
+	Value     []byte
+	LastIndex uint64
+}
 
-	// Atomic delete of a single value
-	AtomicDelete(key string, oldValue []byte, index uint64) (bool, error)
+// WriteOptions contains optional request parameters
+type WriteOptions struct {
+	Heartbeat time.Duration
+	Ephemeral bool
 }
 
-// KVEntry represents {Key, Value, Lastindex} tuple
-type KVEntry interface {
-	Key() string
-	Value() []byte
-	LastIndex() uint64
+// LockOptions contains optional request parameters
+type LockOptions struct {
+	Value []byte        // Optional, value to associate with the lock
+	TTL   time.Duration // Optional, expiration ttl associated with the lock
 }
 
-var (
-	// List of Store services
-	stores map[string]Initialize
-)
+// WatchCallback is used for watch methods on keys
+// and is triggered on key change
+type WatchCallback func(entries ...*KVPair)
 
-func init() {
-	stores = make(map[string]Initialize)
-	stores["consul"] = InitializeConsul
-	stores["etcd"] = InitializeEtcd
-	stores["zk"] = InitializeZookeeper
+// Locker provides locking mechanism on top of the store.
+// Similar to `sync.Lock` except it may return errors.
+type Locker interface {
+	Lock() (<-chan struct{}, error)
+	Unlock() error
 }
 
-// CreateStore creates a an instance of store
-func CreateStore(store string, addrs []string, options Config) (Store, error) {
+// Initialize creates a new Store object, initializing the client
+type Initialize func(addrs []string, options *Config) (Store, error)
+
+var (
+	// Backend initializers
+	initializers = map[Backend]Initialize{
+		MOCK:   InitializeMock,
+		CONSUL: InitializeConsul,
+		ETCD:   InitializeEtcd,
+		ZK:     InitializeZookeeper,
+	}
+)
 
-	if init, exists := stores[store]; exists {
-		log.WithFields(log.Fields{"store": store}).Debug("Initializing store service")
+// NewStore creates a an instance of store
+func NewStore(backend Backend, addrs []string, options *Config) (Store, error) {
+	if init, exists := initializers[backend]; exists {
+		log.WithFields(log.Fields{"backend": backend}).Debug("Initializing store service")
 		return init(addrs, options)
 	}
 

+ 401 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/store_test.go

@@ -0,0 +1,401 @@
+package store
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func testStore(t *testing.T, kv Store) {
+	testPutGetDelete(t, kv)
+	testWatch(t, kv)
+	testWatchTree(t, kv)
+	testAtomicPut(t, kv)
+	testAtomicDelete(t, kv)
+	testLockUnlock(t, kv)
+	testPutEphemeral(t, kv)
+	testList(t, kv)
+	testDeleteTree(t, kv)
+}
+
+func testPutGetDelete(t *testing.T, kv Store) {
+	key := "foo"
+	value := []byte("bar")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Delete the key
+	err = kv.Delete(key)
+	assert.NoError(t, err)
+
+	// Get should fail
+	pair, err = kv.Get(key)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}
+
+func testWatch(t *testing.T, kv Store) {
+	key := "hello"
+	value := []byte("world")
+	newValue := []byte("world!")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	stopCh := make(<-chan struct{})
+	events, err := kv.Watch(key, stopCh)
+	assert.NoError(t, err)
+	assert.NotNil(t, events)
+
+	// Update loop
+	go func() {
+		timeout := time.After(1 * time.Second)
+		tick := time.Tick(250 * time.Millisecond)
+		for {
+			select {
+			case <-timeout:
+				return
+			case <-tick:
+				err := kv.Put(key, newValue, nil)
+				if assert.NoError(t, err) {
+					continue
+				}
+				return
+			}
+		}
+	}()
+
+	// Check for updates
+	timeout := time.After(2 * time.Second)
+	eventCount := 1
+	for {
+		select {
+		case event := <-events:
+			assert.NotNil(t, event)
+			if eventCount == 1 {
+				assert.Equal(t, event.Key, key)
+				assert.Equal(t, event.Value, value)
+			} else {
+				assert.Equal(t, event.Key, key)
+				assert.Equal(t, event.Value, newValue)
+			}
+			eventCount++
+			// We received all the events we wanted to check
+			if eventCount >= 4 {
+				return
+			}
+		case <-timeout:
+			t.Fatal("Timeout reached")
+			return
+		}
+	}
+}
+
+func testWatchTree(t *testing.T, kv Store) {
+	dir := "tree"
+
+	node1 := "tree/node1"
+	value1 := []byte("node1")
+
+	node2 := "tree/node2"
+	value2 := []byte("node2")
+
+	node3 := "tree/node3"
+	value3 := []byte("node3")
+
+	err := kv.Put(node1, value1, nil)
+	assert.NoError(t, err)
+	err = kv.Put(node2, value2, nil)
+	assert.NoError(t, err)
+	err = kv.Put(node3, value3, nil)
+	assert.NoError(t, err)
+
+	stopCh := make(<-chan struct{})
+	events, err := kv.WatchTree(dir, stopCh)
+	assert.NoError(t, err)
+	assert.NotNil(t, events)
+
+	// Update loop
+	go func() {
+		timeout := time.After(250 * time.Millisecond)
+		for {
+			select {
+			case <-timeout:
+				err := kv.Delete(node3)
+				assert.NoError(t, err)
+				return
+			}
+		}
+	}()
+
+	// Check for updates
+	timeout := time.After(4 * time.Second)
+	for {
+		select {
+		case event := <-events:
+			assert.NotNil(t, event)
+			// We received the Delete event on a child node
+			// Exit test successfully
+			if len(event) == 2 {
+				return
+			}
+		case <-timeout:
+			t.Fatal("Timeout reached")
+			return
+		}
+	}
+}
+
+func testAtomicPut(t *testing.T, kv Store) {
+	key := "hello"
+	value := []byte("world")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// This CAS should succeed
+	success, _, err := kv.AtomicPut("hello", []byte("WORLD"), pair, nil)
+	assert.NoError(t, err)
+	assert.True(t, success)
+
+	// This CAS should fail
+	pair.LastIndex = 0
+	success, _, err = kv.AtomicPut("hello", []byte("WORLDWORLD"), pair, nil)
+	assert.Error(t, err)
+	assert.False(t, success)
+}
+
+func testAtomicDelete(t *testing.T, kv Store) {
+	key := "atomic"
+	value := []byte("world")
+
+	// Put the key
+	err := kv.Put(key, value, nil)
+	assert.NoError(t, err)
+
+	// Get should return the value and an incremented index
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	tempIndex := pair.LastIndex
+
+	// AtomicDelete should fail
+	pair.LastIndex = 0
+	success, err := kv.AtomicDelete(key, pair)
+	assert.Error(t, err)
+	assert.False(t, success)
+
+	// AtomicDelete should succeed
+	pair.LastIndex = tempIndex
+	success, err = kv.AtomicDelete(key, pair)
+	assert.NoError(t, err)
+	assert.True(t, success)
+}
+
+func testLockUnlock(t *testing.T, kv Store) {
+	t.Parallel()
+
+	key := "foo"
+	value := []byte("bar")
+
+	// We should be able to create a new lock on key
+	lock, err := kv.NewLock(key, &LockOptions{Value: value})
+	assert.NoError(t, err)
+	assert.NotNil(t, lock)
+
+	// Lock should successfully succeed or block
+	lockChan, err := lock.Lock()
+	assert.NoError(t, err)
+	assert.NotNil(t, lockChan)
+
+	// Get should work
+	pair, err := kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Unlock should succeed
+	err = lock.Unlock()
+	assert.NoError(t, err)
+
+	// Get should work
+	pair, err = kv.Get(key)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, value)
+	assert.NotEqual(t, pair.LastIndex, 0)
+}
+
+// FIXME Gracefully handle Zookeeper
+func testPutEphemeral(t *testing.T, kv Store) {
+	// Zookeeper: initialize client here (Close() hangs otherwise)
+	zookeeper := false
+	if _, ok := kv.(*Zookeeper); ok {
+		zookeeper = true
+		kv = makeZkClient(t)
+	}
+
+	firstKey := "first"
+	firstValue := []byte("foo")
+
+	secondKey := "second"
+	secondValue := []byte("bar")
+
+	// Put the first key with the Ephemeral flag
+	err := kv.Put(firstKey, firstValue, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Put a second key with the Ephemeral flag
+	err = kv.Put(secondKey, secondValue, &WriteOptions{Ephemeral: true})
+	assert.NoError(t, err)
+
+	// Get on firstKey should work
+	pair, err := kv.Get(firstKey)
+	assert.NoError(t, err)
+	assert.NotNil(t, pair)
+
+	// Get on secondKey should work
+	pair, err = kv.Get(secondKey)
+	assert.NoError(t, err)
+	assert.NotNil(t, pair)
+
+	// Zookeeper: close client connection
+	if zookeeper {
+		kv.Close()
+	}
+
+	// Let the session expire
+	time.Sleep(5 * time.Second)
+
+	// Zookeeper: re-create the client
+	if zookeeper {
+		kv = makeZkClient(t)
+	}
+
+	// Get on firstKey shouldn't work
+	pair, err = kv.Get(firstKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+
+	// Get on secondKey shouldn't work
+	pair, err = kv.Get(secondKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}
+
+func testList(t *testing.T, kv Store) {
+	prefix := "nodes"
+
+	firstKey := "nodes/first"
+	firstValue := []byte("first")
+
+	secondKey := "nodes/second"
+	secondValue := []byte("second")
+
+	// Put the first key
+	err := kv.Put(firstKey, firstValue, nil)
+	assert.NoError(t, err)
+
+	// Put the second key
+	err = kv.Put(secondKey, secondValue, nil)
+	assert.NoError(t, err)
+
+	// List should work and return the two correct values
+	pairs, err := kv.List(prefix)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pairs) {
+		assert.Equal(t, len(pairs), 2)
+	}
+
+	// Check pairs, those are not necessarily in Put order
+	for _, pair := range pairs {
+		if pair.Key == firstKey {
+			assert.Equal(t, pair.Value, firstValue)
+		}
+		if pair.Key == secondKey {
+			assert.Equal(t, pair.Value, secondValue)
+		}
+	}
+}
+
+func testDeleteTree(t *testing.T, kv Store) {
+	prefix := "nodes"
+
+	firstKey := "nodes/first"
+	firstValue := []byte("first")
+
+	secondKey := "nodes/second"
+	secondValue := []byte("second")
+
+	// Put the first key
+	err := kv.Put(firstKey, firstValue, nil)
+	assert.NoError(t, err)
+
+	// Put the second key
+	err = kv.Put(secondKey, secondValue, nil)
+	assert.NoError(t, err)
+
+	// Get should work on the first Key
+	pair, err := kv.Get(firstKey)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, firstValue)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Get should work on the second Key
+	pair, err = kv.Get(secondKey)
+	assert.NoError(t, err)
+	if assert.NotNil(t, pair) {
+		assert.NotNil(t, pair.Value)
+	}
+	assert.Equal(t, pair.Value, secondValue)
+	assert.NotEqual(t, pair.LastIndex, 0)
+
+	// Delete Values under directory `nodes`
+	err = kv.DeleteTree(prefix)
+	assert.NoError(t, err)
+
+	// Get should fail on both keys
+	pair, err = kv.Get(firstKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+
+	pair, err = kv.Get(secondKey)
+	assert.Error(t, err)
+	assert.Nil(t, pair)
+}

+ 0 - 60
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/structs.go

@@ -1,60 +0,0 @@
-package store
-
-import (
-	"crypto/tls"
-	"errors"
-	"time"
-)
-
-var (
-	// ErrNotSupported is exported
-	ErrNotSupported = errors.New("Backend storage not supported yet, please choose another one")
-	// ErrNotImplemented is exported
-	ErrNotImplemented = errors.New("Call not implemented in current backend")
-	// ErrNotReachable is exported
-	ErrNotReachable = errors.New("Api not reachable")
-	// ErrCannotLock is exported
-	ErrCannotLock = errors.New("Error acquiring the lock")
-	// ErrWatchDoesNotExist is exported
-	ErrWatchDoesNotExist = errors.New("No watch found for specified key")
-	// ErrKeyModified is exported
-	ErrKeyModified = errors.New("Unable to complete atomic operation, key modified")
-	// ErrKeyNotFound is exported
-	ErrKeyNotFound = errors.New("Key not found in store")
-)
-
-// KV represents the different supported K/V
-type KV string
-
-const (
-	// CONSUL is exported
-	CONSUL KV = "consul"
-	// ETCD is exported
-	ETCD = "etcd"
-	// ZOOKEEPER is exported
-	ZOOKEEPER = "zookeeper"
-)
-
-// Config contains the options for a storage client
-type Config struct {
-	TLS     *tls.Config
-	Timeout time.Duration
-}
-
-type kviTuple struct {
-	key       string
-	value     []byte
-	lastIndex uint64
-}
-
-func (kvi *kviTuple) Key() string {
-	return kvi.key
-}
-
-func (kvi *kviTuple) Value() []byte {
-	return kvi.value
-}
-
-func (kvi *kviTuple) LastIndex() uint64 {
-	return kvi.lastIndex
-}

+ 192 - 94
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper.go

@@ -8,23 +8,32 @@ import (
 	zk "github.com/samuel/go-zookeeper/zk"
 )
 
+const defaultTimeout = 10 * time.Second
+
 // Zookeeper embeds the zookeeper client
-// and list of watches
 type Zookeeper struct {
 	timeout time.Duration
 	client  *zk.Conn
-	watches map[string]<-chan zk.Event
+}
+
+type zookeeperLock struct {
+	client *zk.Conn
+	lock   *zk.Lock
+	key    string
+	value  []byte
 }
 
 // InitializeZookeeper creates a new Zookeeper client
 // given a list of endpoints and optional tls config
-func InitializeZookeeper(endpoints []string, options Config) (Store, error) {
+func InitializeZookeeper(endpoints []string, options *Config) (Store, error) {
 	s := &Zookeeper{}
-	s.watches = make(map[string]<-chan zk.Event)
-	s.timeout = 5 * time.Second // default timeout
+	s.timeout = defaultTimeout
 
-	if options.Timeout != 0 {
-		s.setTimeout(options.Timeout)
+	// Set options
+	if options != nil {
+		if options.ConnectionTimeout != 0 {
+			s.setTimeout(options.ConnectionTimeout)
+		}
 	}
 
 	conn, _, err := zk.Connect(endpoints, s.timeout)
@@ -43,21 +52,25 @@ func (s *Zookeeper) setTimeout(time time.Duration) {
 
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
-func (s *Zookeeper) Get(key string) (value []byte, lastIndex uint64, err error) {
-	resp, meta, err := s.client.Get(format(key))
+func (s *Zookeeper) Get(key string) (*KVPair, error) {
+	resp, meta, err := s.client.Get(normalize(key))
 	if err != nil {
-		return nil, 0, err
+		return nil, err
 	}
 	if resp == nil {
-		return nil, 0, ErrKeyNotFound
+		return nil, ErrKeyNotFound
 	}
-	return resp, uint64(meta.Mzxid), nil
+	return &KVPair{key, resp, uint64(meta.Version)}, nil
 }
 
 // Create the entire path for a directory that does not exist
-func (s *Zookeeper) createFullpath(path []string) error {
+func (s *Zookeeper) createFullpath(path []string, ephemeral bool) error {
 	for i := 1; i <= len(path); i++ {
 		newpath := "/" + strings.Join(path[:i], "/")
+		if i == len(path) && ephemeral {
+			_, err := s.client.Create(newpath, []byte{1}, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
+			return err
+		}
 		_, err := s.client.Create(newpath, []byte{1}, 0, zk.WorldACL(zk.PermAll))
 		if err != nil {
 			// Skip if node already exists
@@ -70,14 +83,18 @@ func (s *Zookeeper) createFullpath(path []string) error {
 }
 
 // Put a value at "key"
-func (s *Zookeeper) Put(key string, value []byte) error {
-	fkey := format(key)
+func (s *Zookeeper) Put(key string, value []byte, opts *WriteOptions) error {
+	fkey := normalize(key)
 	exists, err := s.Exists(key)
 	if err != nil {
 		return err
 	}
 	if !exists {
-		s.createFullpath(splitKey(key))
+		if opts != nil && opts.Ephemeral {
+			s.createFullpath(splitKey(key), opts.Ephemeral)
+		} else {
+			s.createFullpath(splitKey(key), false)
+		}
 	}
 	_, err = s.client.Set(fkey, value, -1)
 	return err
@@ -85,129 +102,210 @@ func (s *Zookeeper) Put(key string, value []byte) error {
 
 // Delete a value at "key"
 func (s *Zookeeper) Delete(key string) error {
-	err := s.client.Delete(format(key), -1)
+	err := s.client.Delete(normalize(key), -1)
 	return err
 }
 
 // Exists checks if the key exists inside the store
 func (s *Zookeeper) Exists(key string) (bool, error) {
-	exists, _, err := s.client.Exists(format(key))
+	exists, _, err := s.client.Exists(normalize(key))
 	if err != nil {
 		return false, err
 	}
 	return exists, nil
 }
 
-// Watch a single key for modifications
-func (s *Zookeeper) Watch(key string, _ time.Duration, callback WatchCallback) error {
-	fkey := format(key)
-	_, _, eventChan, err := s.client.GetW(fkey)
+// Watch changes on a key.
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Zookeeper) Watch(key string, stopCh <-chan struct{}) (<-chan *KVPair, error) {
+	fkey := normalize(key)
+	pair, err := s.Get(key)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	// Create a new Watch entry with eventChan
-	s.watches[fkey] = eventChan
+	// Catch zk notifications and fire changes into the channel.
+	watchCh := make(chan *KVPair)
+	go func() {
+		defer close(watchCh)
 
-	for e := range eventChan {
-		if e.Type == zk.EventNodeChildrenChanged {
-			log.WithField("name", "zk").Debug("Discovery watch triggered")
-			entry, index, err := s.Get(key)
-			kvi := []KVEntry{&kviTuple{key, []byte(entry), index}}
-			if err == nil {
-				callback(kvi)
+		// Get returns the current value before setting the watch.
+		watchCh <- pair
+		for {
+			_, _, eventCh, err := s.client.GetW(fkey)
+			if err != nil {
+				return
+			}
+			select {
+			case e := <-eventCh:
+				if e.Type == zk.EventNodeDataChanged {
+					if entry, err := s.Get(key); err == nil {
+						watchCh <- entry
+					}
+				}
+			case <-stopCh:
+				// There is no way to stop GetW so just quit
+				return
 			}
 		}
-	}
+	}()
 
-	return nil
+	return watchCh, nil
 }
 
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *Zookeeper) CancelWatch(key string) error {
-	key = format(key)
-	if _, ok := s.watches[key]; !ok {
-		log.Error("Chan does not exist for key: ", key)
-		return ErrWatchDoesNotExist
+// WatchTree watches changes on a "directory"
+// Returns a channel that will receive changes or an error.
+// Upon creating a watch, the current value will be sent to the channel.
+// Providing a non-nil stopCh can be used to stop watching.
+func (s *Zookeeper) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*KVPair, error) {
+	fprefix := normalize(prefix)
+	entries, err := s.List(prefix)
+	if err != nil {
+		return nil, err
 	}
-	// Just remove the entry on watches key
-	s.watches[key] = nil
-	return nil
+
+	// Catch zk notifications and fire changes into the channel.
+	watchCh := make(chan []*KVPair)
+	go func() {
+		defer close(watchCh)
+
+		// List returns the current values before setting the watch.
+		watchCh <- entries
+
+		for {
+			_, _, eventCh, err := s.client.ChildrenW(fprefix)
+			if err != nil {
+				return
+			}
+			select {
+			case e := <-eventCh:
+				if e.Type == zk.EventNodeChildrenChanged {
+					if kv, err := s.List(prefix); err == nil {
+						watchCh <- kv
+					}
+				}
+			case <-stopCh:
+				// There is no way to stop GetW so just quit
+				return
+			}
+		}
+	}()
+
+	return watchCh, nil
 }
 
-// GetRange gets a range of values at "directory"
-func (s *Zookeeper) GetRange(prefix string) (kvi []KVEntry, err error) {
-	prefix = format(prefix)
-	entries, stat, err := s.client.Children(prefix)
+// List the content of a given prefix
+func (s *Zookeeper) List(prefix string) ([]*KVPair, error) {
+	keys, stat, err := s.client.Children(normalize(prefix))
 	if err != nil {
-		log.Error("Cannot fetch range of keys beginning with prefix: ", prefix)
 		return nil, err
 	}
-	for _, item := range entries {
-		kvi = append(kvi, &kviTuple{prefix, []byte(item), uint64(stat.Mzxid)})
+	kv := []*KVPair{}
+	for _, key := range keys {
+		// FIXME Costly Get request for each child key..
+		pair, err := s.Get(prefix + normalize(key))
+		if err != nil {
+			return nil, err
+		}
+		kv = append(kv, &KVPair{key, []byte(pair.Value), uint64(stat.Version)})
 	}
-	return kvi, err
+	return kv, nil
 }
 
-// DeleteRange deletes a range of values at "directory"
-func (s *Zookeeper) DeleteRange(prefix string) error {
-	err := s.client.Delete(format(prefix), -1)
+// DeleteTree deletes a range of keys based on prefix
+func (s *Zookeeper) DeleteTree(prefix string) error {
+	pairs, err := s.List(prefix)
+	if err != nil {
+		return err
+	}
+	var reqs []interface{}
+	for _, pair := range pairs {
+		reqs = append(reqs, &zk.DeleteRequest{
+			Path:    normalize(prefix + "/" + pair.Key),
+			Version: -1,
+		})
+	}
+	_, err = s.client.Multi(reqs...)
 	return err
 }
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *Zookeeper) WatchRange(prefix string, filter string, _ time.Duration, callback WatchCallback) error {
-	fprefix := format(prefix)
-	_, _, eventChan, err := s.client.ChildrenW(fprefix)
+// AtomicPut put a value at "key" if the key has not been
+// modified in the meantime, throws an error if this is the case
+func (s *Zookeeper) AtomicPut(key string, value []byte, previous *KVPair, _ *WriteOptions) (bool, *KVPair, error) {
+	if previous == nil {
+		return false, nil, ErrPreviousNotSpecified
+	}
+
+	meta, err := s.client.Set(normalize(key), value, int32(previous.LastIndex))
 	if err != nil {
-		return err
+		if err == zk.ErrBadVersion {
+			return false, nil, ErrKeyModified
+		}
+		return false, nil, err
 	}
+	return true, &KVPair{Key: key, Value: value, LastIndex: uint64(meta.Version)}, nil
+}
 
-	// Create a new Watch entry with eventChan
-	s.watches[fprefix] = eventChan
+// AtomicDelete deletes a value at "key" if the key has not
+// been modified in the meantime, throws an error if this is the case
+func (s *Zookeeper) AtomicDelete(key string, previous *KVPair) (bool, error) {
+	if previous == nil {
+		return false, ErrPreviousNotSpecified
+	}
 
-	for e := range eventChan {
-		if e.Type == zk.EventNodeChildrenChanged {
-			log.WithField("name", "zk").Debug("Discovery watch triggered")
-			kvi, err := s.GetRange(prefix)
-			if err == nil {
-				callback(kvi)
-			}
+	err := s.client.Delete(normalize(key), int32(previous.LastIndex))
+	if err != nil {
+		if err == zk.ErrBadVersion {
+			return false, ErrKeyModified
 		}
+		return false, err
 	}
-
-	return nil
+	return true, nil
 }
 
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *Zookeeper) CancelWatchRange(prefix string) error {
-	return s.CancelWatch(prefix)
-}
+// NewLock returns a handle to a lock struct which can be used to acquire and
+// release the mutex.
+func (s *Zookeeper) NewLock(key string, options *LockOptions) (Locker, error) {
+	value := []byte("")
 
-// AtomicPut put a value at "key" if the key has not been
-// modified in the meantime, throws an error if this is the case
-func (s *Zookeeper) AtomicPut(key string, oldValue []byte, newValue []byte, index uint64) (bool, error) {
-	// Use index of Set method to implement CAS
-	return false, ErrNotImplemented
+	// Apply options
+	if options != nil {
+		if options.Value != nil {
+			value = options.Value
+		}
+	}
+
+	return &zookeeperLock{
+		client: s.client,
+		key:    normalize(key),
+		value:  value,
+		lock:   zk.NewLock(s.client, normalize(key), zk.WorldACL(zk.PermAll)),
+	}, nil
 }
 
-// AtomicDelete deletes a value at "key" if the key has not
-// been modified in the meantime, throws an error if this is the case
-func (s *Zookeeper) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
-	return false, ErrNotImplemented
+// Lock attempts to acquire the lock and blocks while doing so.
+// Returns a channel that is closed if our lock is lost or an error.
+func (l *zookeeperLock) Lock() (<-chan struct{}, error) {
+	err := l.lock.Lock()
+
+	if err == nil {
+		// We hold the lock, we can set our value
+		// FIXME: When the last leader leaves the election, this value will be left behind
+		_, err = l.client.Set(l.key, l.value, -1)
+	}
+
+	return make(chan struct{}), err
 }
 
-// Acquire the lock for "key"/"directory"
-func (s *Zookeeper) Acquire(path string, value []byte) (string, error) {
-	// lock := zk.NewLock(s.client, path, nil)
-	// locks[path] = lock
-	// lock.Lock()
-	return "", ErrNotImplemented
+// Unlock released the lock. It is an error to call this
+// if the lock is not currently held.
+func (l *zookeeperLock) Unlock() error {
+	return l.lock.Unlock()
 }
 
-// Release the lock for "key"/"directory"
-func (s *Zookeeper) Release(session string) error {
-	return ErrNotImplemented
+// Close closes the client connection
+func (s *Zookeeper) Close() {
+	s.client.Close()
 }

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/swarm/pkg/store/zookeeper_test.go

@@ -0,0 +1,30 @@
+package store
+
+import (
+	"testing"
+	"time"
+)
+
+func makeZkClient(t *testing.T) Store {
+	client := "localhost:2181"
+
+	kv, err := NewStore(
+		ZK,
+		[]string{client},
+		&Config{
+			ConnectionTimeout: 3 * time.Second,
+			EphemeralTTL:      2 * time.Second,
+		},
+	)
+	if err != nil {
+		t.Fatalf("cannot create store: %v", err)
+	}
+
+	return kv
+}
+
+func TestZkStore(t *testing.T) {
+	kv := makeZkClient(t)
+
+	testStore(t, kv)
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/.gitignore

@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe

+ 23 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/LICENSE.md

@@ -0,0 +1,23 @@
+objx - by Mat Ryer and Tyler Bunnell
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Stretchr, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 3 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/README.md

@@ -0,0 +1,3 @@
+# objx
+
+  * Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)

+ 179 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors.go

@@ -0,0 +1,179 @@
+package objx
+
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// arrayAccesRegexString is the regex used to extract the array number
+// from the access path
+const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
+
+// arrayAccesRegex is the compiled arrayAccesRegexString
+var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
+
+// Get gets the value using the specified selector and
+// returns it inside a new Obj object.
+//
+// If it cannot find the value, Get will return a nil
+// value inside an instance of Obj.
+//
+// Get can only operate directly on map[string]interface{} and []interface.
+//
+// Example
+//
+// To access the title of the third chapter of the second book, do:
+//
+//    o.Get("books[1].chapters[2].title")
+func (m Map) Get(selector string) *Value {
+	rawObj := access(m, selector, nil, false, false)
+	return &Value{data: rawObj}
+}
+
+// Set sets the value using the specified selector and
+// returns the object on which Set was called.
+//
+// Set can only operate directly on map[string]interface{} and []interface
+//
+// Example
+//
+// To set the title of the third chapter of the second book, do:
+//
+//    o.Set("books[1].chapters[2].title","Time to Go")
+func (m Map) Set(selector string, value interface{}) Map {
+	access(m, selector, value, true, false)
+	return m
+}
+
+// access accesses the object using the selector and performs the
+// appropriate action.
+func access(current, selector, value interface{}, isSet, panics bool) interface{} {
+
+	switch selector.(type) {
+	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+
+		if array, ok := current.([]interface{}); ok {
+			index := intFromInterface(selector)
+
+			if index >= len(array) {
+				if panics {
+					panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+				}
+				return nil
+			}
+
+			return array[index]
+		}
+
+		return nil
+
+	case string:
+
+		selStr := selector.(string)
+		selSegs := strings.SplitN(selStr, PathSeparator, 2)
+		thisSel := selSegs[0]
+		index := -1
+		var err error
+
+		// https://github.com/stretchr/objx/issues/12
+		if strings.Contains(thisSel, "[") {
+
+			arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
+
+			if len(arrayMatches) > 0 {
+
+				// Get the key into the map
+				thisSel = arrayMatches[1]
+
+				// Get the index into the array at the key
+				index, err = strconv.Atoi(arrayMatches[2])
+
+				if err != nil {
+					// This should never happen. If it does, something has gone
+					// seriously wrong. Panic.
+					panic("objx: Array index is not an integer.  Must use array[int].")
+				}
+
+			}
+		}
+
+		if curMap, ok := current.(Map); ok {
+			current = map[string]interface{}(curMap)
+		}
+
+		// get the object in question
+		switch current.(type) {
+		case map[string]interface{}:
+			curMSI := current.(map[string]interface{})
+			if len(selSegs) <= 1 && isSet {
+				curMSI[thisSel] = value
+				return nil
+			} else {
+				current = curMSI[thisSel]
+			}
+		default:
+			current = nil
+		}
+
+		if current == nil && panics {
+			panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
+		}
+
+		// do we need to access the item of an array?
+		if index > -1 {
+			if array, ok := current.([]interface{}); ok {
+				if index < len(array) {
+					current = array[index]
+				} else {
+					if panics {
+						panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+					}
+					current = nil
+				}
+			}
+		}
+
+		if len(selSegs) > 1 {
+			current = access(current, selSegs[1], value, isSet, panics)
+		}
+
+	}
+
+	return current
+
+}
+
+// intFromInterface converts an interface object to the largest
+// representation of an unsigned integer using a type switch and
+// assertions
+func intFromInterface(selector interface{}) int {
+	var value int
+	switch selector.(type) {
+	case int:
+		value = selector.(int)
+	case int8:
+		value = int(selector.(int8))
+	case int16:
+		value = int(selector.(int16))
+	case int32:
+		value = int(selector.(int32))
+	case int64:
+		value = int(selector.(int64))
+	case uint:
+		value = int(selector.(uint))
+	case uint8:
+		value = int(selector.(uint8))
+	case uint16:
+		value = int(selector.(uint16))
+	case uint32:
+		value = int(selector.(uint32))
+	case uint64:
+		value = int(selector.(uint64))
+	default:
+		panic("objx: array access argument is not an integer type (this should never happen)")
+	}
+
+	return value
+}

+ 145 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go

@@ -0,0 +1,145 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestAccessorsAccessGetSingleField(t *testing.T) {
+
+	current := map[string]interface{}{"name": "Tyler"}
+	assert.Equal(t, "Tyler", access(current, "name", nil, false, true))
+
+}
+func TestAccessorsAccessGetDeep(t *testing.T) {
+
+	current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
+	assert.Equal(t, "Tyler", access(current, "name.first", nil, false, true))
+	assert.Equal(t, "Bunnell", access(current, "name.last", nil, false, true))
+
+}
+func TestAccessorsAccessGetDeepDeep(t *testing.T) {
+
+	current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
+	assert.Equal(t, 4, access(current, "one.two.three.four", nil, false, true))
+
+}
+func TestAccessorsAccessGetInsideArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
+	assert.Equal(t, "Tyler", access(current, "names[0].first", nil, false, true))
+	assert.Equal(t, "Bunnell", access(current, "names[0].last", nil, false, true))
+	assert.Equal(t, "Capitol", access(current, "names[1].first", nil, false, true))
+	assert.Equal(t, "Bollocks", access(current, "names[1].last", nil, false, true))
+
+	assert.Panics(t, func() {
+		access(current, "names[2]", nil, false, true)
+	})
+	assert.Nil(t, access(current, "names[2]", nil, false, false))
+
+}
+
+func TestAccessorsAccessGetFromArrayWithInt(t *testing.T) {
+
+	current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
+	one := access(current, 0, nil, false, false)
+	two := access(current, 1, nil, false, false)
+	three := access(current, 2, nil, false, false)
+
+	assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
+	assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
+	assert.Nil(t, three)
+
+}
+
+func TestAccessorsGet(t *testing.T) {
+
+	current := New(map[string]interface{}{"name": "Tyler"})
+	assert.Equal(t, "Tyler", current.Get("name").data)
+
+}
+
+func TestAccessorsAccessSetSingleField(t *testing.T) {
+
+	current := map[string]interface{}{"name": "Tyler"}
+	access(current, "name", "Mat", true, false)
+	assert.Equal(t, current["name"], "Mat")
+
+	access(current, "age", 29, true, true)
+	assert.Equal(t, current["age"], 29)
+
+}
+
+func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) {
+
+	current := map[string]interface{}{}
+	access(current, "name", "Mat", true, false)
+	assert.Equal(t, current["name"], "Mat")
+
+}
+
+func TestAccessorsAccessSetDeep(t *testing.T) {
+
+	current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
+
+	access(current, "name.first", "Mat", true, true)
+	access(current, "name.last", "Ryer", true, true)
+
+	assert.Equal(t, "Mat", access(current, "name.first", nil, false, true))
+	assert.Equal(t, "Ryer", access(current, "name.last", nil, false, true))
+
+}
+func TestAccessorsAccessSetDeepDeep(t *testing.T) {
+
+	current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
+
+	access(current, "one.two.three.four", 5, true, true)
+
+	assert.Equal(t, 5, access(current, "one.two.three.four", nil, false, true))
+
+}
+func TestAccessorsAccessSetArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{"Tyler"}}
+
+	access(current, "names[0]", "Mat", true, true)
+
+	assert.Equal(t, "Mat", access(current, "names[0]", nil, false, true))
+
+}
+func TestAccessorsAccessSetInsideArray(t *testing.T) {
+
+	current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
+
+	access(current, "names[0].first", "Mat", true, true)
+	access(current, "names[0].last", "Ryer", true, true)
+	access(current, "names[1].first", "Captain", true, true)
+	access(current, "names[1].last", "Underpants", true, true)
+
+	assert.Equal(t, "Mat", access(current, "names[0].first", nil, false, true))
+	assert.Equal(t, "Ryer", access(current, "names[0].last", nil, false, true))
+	assert.Equal(t, "Captain", access(current, "names[1].first", nil, false, true))
+	assert.Equal(t, "Underpants", access(current, "names[1].last", nil, false, true))
+
+}
+
+func TestAccessorsAccessSetFromArrayWithInt(t *testing.T) {
+
+	current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
+	one := access(current, 0, nil, false, false)
+	two := access(current, 1, nil, false, false)
+	three := access(current, 2, nil, false, false)
+
+	assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
+	assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
+	assert.Nil(t, three)
+
+}
+
+func TestAccessorsSet(t *testing.T) {
+
+	current := New(map[string]interface{}{"name": "Tyler"})
+	current.Set("name", "Mat")
+	assert.Equal(t, "Mat", current.Get("name").data)
+
+}

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/array-access.txt

@@ -0,0 +1,14 @@
+  case []{1}:
+    a := object.([]{1})
+    if isSet {
+      a[index] = value.({1})
+    } else {
+      if index >= len(a) {
+        if panics {
+          panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
+        }
+        return nil
+      } else {
+        return a[index]
+      }
+    }

+ 86 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/index.html

@@ -0,0 +1,86 @@
+<html>
+	<head>
+	<title>
+		Codegen
+	</title>
+	<style>
+		body {
+			width: 800px;
+			margin: auto;
+		}
+		textarea {
+			width: 100%;
+			min-height: 100px;
+			font-family: Courier;
+		}
+	</style>
+	</head>
+	<body>
+
+		<h2>
+			Template
+		</h2>
+		<p>
+			Use <code>{x}</code> as a placeholder for each argument.
+		</p>
+		<textarea id="template"></textarea>
+
+		<h2>
+			Arguments (comma separated)
+		</h2>
+		<p>
+			One block per line
+		</p>
+		<textarea id="args"></textarea>
+
+		<h2>
+			Output
+		</h2>
+		<input id="go" type="button" value="Generate code" />
+
+		<textarea id="output"></textarea>
+
+		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+		<script>
+
+			$(function(){
+
+				$("#go").click(function(){
+
+					var output = ""
+					var template = $("#template").val()
+					var args = $("#args").val()
+
+					// collect the args
+					var argLines = args.split("\n")
+					for (var line in argLines) {
+
+						var argLine = argLines[line];
+						var thisTemp = template
+
+						// get individual args
+						var args = argLine.split(",")
+
+						for (var argI in args) {
+							var argText = args[argI];
+							var argPlaceholder = "{" + argI + "}";
+
+							while (thisTemp.indexOf(argPlaceholder) > -1) {
+								thisTemp = thisTemp.replace(argPlaceholder, argText);
+							}
+
+						}
+
+						output += thisTemp
+
+					}
+
+					$("#output").val(output);
+
+				});
+
+			});
+
+		</script>
+	</body>
+</html>

+ 286 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/template.txt

@@ -0,0 +1,286 @@
+/*
+	{4} ({1} and []{1})
+	--------------------------------------------------
+*/
+
+// {4} gets the value as a {1}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) {4}(optionalDefault ...{1}) {1} {
+	if s, ok := v.data.({1}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return {3}
+}
+
+// Must{4} gets the value as a {1}.
+//
+// Panics if the object is not a {1}.
+func (v *Value) Must{4}() {1} {
+	return v.data.({1})
+}
+
+// {4}Slice gets the value as a []{1}, returns the optionalDefault
+// value or nil if the value is not a []{1}.
+func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
+	if s, ok := v.data.([]{1}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// Must{4}Slice gets the value as a []{1}.
+//
+// Panics if the object is not a []{1}.
+func (v *Value) Must{4}Slice() []{1} {
+	return v.data.([]{1})
+}
+
+// Is{4} gets whether the object contained is a {1} or not.
+func (v *Value) Is{4}() bool {
+  _, ok := v.data.({1})
+  return ok
+}
+
+// Is{4}Slice gets whether the object contained is a []{1} or not.
+func (v *Value) Is{4}Slice() bool {
+	_, ok := v.data.([]{1})
+	return ok
+}
+
+// Each{4} calls the specified callback for each object
+// in the []{1}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
+
+	for index, val := range v.Must{4}Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// Where{4} uses the specified decider function to select items
+// from the []{1}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
+
+	var selected []{1}
+
+	v.Each{4}(func(index int, val {1}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data:selected}
+
+}
+
+// Group{4} uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]{1}.
+func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
+
+	groups := make(map[string][]{1})
+
+	v.Each{4}(func(index int, val {1}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]{1}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data:groups}
+
+}
+
+// Replace{4} uses the specified function to replace each {1}s
+// by iterating each item.  The data in the returned result will be a
+// []{1} containing the replaced items.
+func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
+
+	arr := v.Must{4}Slice()
+	replaced := make([]{1}, len(arr))
+
+	v.Each{4}(func(index int, val {1}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data:replaced}
+
+}
+
+// Collect{4} uses the specified collector function to collect a value
+// for each of the {1}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
+
+	arr := v.Must{4}Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.Each{4}(func(index int, val {1}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data:collected}
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func Test{4}(t *testing.T) {
+
+  val := {1}( {2} )
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").{4}())
+	assert.Equal(t, val, New(m).Get("value").Must{4}())
+	assert.Equal(t, {1}({3}), New(m).Get("nothing").{4}())
+	assert.Equal(t, val, New(m).Get("nothing").{4}({2}))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").Must{4}()
+	})
+
+}
+
+func Test{4}Slice(t *testing.T) {
+
+  val := {1}( {2} )
+	m := map[string]interface{}{"value": []{1}{ val }, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").{4}Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").Must{4}Slice()[0])
+	assert.Equal(t, []{1}(nil), New(m).Get("nothing").{4}Slice())
+	assert.Equal(t, val, New(m).Get("nothing").{4}Slice( []{1}{ {1}({2}) } )[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").Must{4}Slice()
+	})
+
+}
+
+func TestIs{4}(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: {1}({2})}
+	assert.True(t, v.Is{4}())
+
+	v = &Value{data: []{1}{ {1}({2}) }}
+	assert.True(t, v.Is{4}Slice())
+
+}
+
+func TestEach{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+	count := 0
+	replacedVals := make([]{1}, 0)
+	assert.Equal(t, v, v.Each{4}(func(i int, val {1}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.Must{4}Slice()[0])
+	assert.Equal(t, replacedVals[1], v.Must{4}Slice()[1])
+	assert.Equal(t, replacedVals[2], v.Must{4}Slice()[2])
+
+}
+
+func TestWhere{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	selected := v.Where{4}(func(i int, val {1}) bool {
+		return i%2==0
+	}).Must{4}Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroup{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	grouped := v.Group{4}(func(i int, val {1}) string {
+		return fmt.Sprintf("%v", i%2==0)
+	}).data.(map[string][]{1})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplace{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	rawArr := v.Must{4}Slice()
+
+	replaced := v.Replace{4}(func(index int, val {1}) {1} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.Must{4}Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollect{4}(t *testing.T) {
+
+	v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+	collected := v.Collect{4}(func(index int, val {1}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/codegen/types_list.txt

@@ -0,0 +1,20 @@
+Interface,interface{},"something",nil,Inter
+Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI
+ObjxMap,(Map),New(1),New(nil),ObjxMap
+Bool,bool,true,false,Bool
+String,string,"hello","",Str
+Int,int,1,0,Int
+Int8,int8,1,0,Int8
+Int16,int16,1,0,Int16
+Int32,int32,1,0,Int32
+Int64,int64,1,0,Int64
+Uint,uint,1,0,Uint
+Uint8,uint8,1,0,Uint8
+Uint16,uint16,1,0,Uint16
+Uint32,uint32,1,0,Uint32
+Uint64,uint64,1,0,Uint64
+Uintptr,uintptr,1,0,Uintptr
+Float32,float32,1,0,Float32
+Float64,float64,1,0,Float64
+Complex64,complex64,1,0,Complex64
+Complex128,complex128,1,0,Complex128

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/constants.go

@@ -0,0 +1,13 @@
+package objx
+
+const (
+	// PathSeparator is the character used to separate the elements
+	// of the keypath.
+	//
+	// For example, `location.address.city`
+	PathSeparator string = "."
+
+	// SignatureSeparator is the character that is used to
+	// separate the Base64 string from the security signature.
+	SignatureSeparator = "_"
+)

+ 117 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions.go

@@ -0,0 +1,117 @@
+package objx
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/url"
+)
+
+// JSON converts the contained object to a JSON string
+// representation
+func (m Map) JSON() (string, error) {
+
+	result, err := json.Marshal(m)
+
+	if err != nil {
+		err = errors.New("objx: JSON encode failed with: " + err.Error())
+	}
+
+	return string(result), err
+
+}
+
+// MustJSON converts the contained object to a JSON string
+// representation and panics if there is an error
+func (m Map) MustJSON() string {
+	result, err := m.JSON()
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+// Base64 converts the contained object to a Base64 string
+// representation of the JSON string representation
+func (m Map) Base64() (string, error) {
+
+	var buf bytes.Buffer
+
+	jsonData, err := m.JSON()
+	if err != nil {
+		return "", err
+	}
+
+	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
+	encoder.Write([]byte(jsonData))
+	encoder.Close()
+
+	return buf.String(), nil
+
+}
+
+// MustBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and panics
+// if there is an error
+func (m Map) MustBase64() string {
+	result, err := m.Base64()
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+// SignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key.
+func (m Map) SignedBase64(key string) (string, error) {
+
+	base64, err := m.Base64()
+	if err != nil {
+		return "", err
+	}
+
+	sig := HashWithKey(base64, key)
+
+	return base64 + SignatureSeparator + sig, nil
+
+}
+
+// MustSignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key and panics if there is an error
+func (m Map) MustSignedBase64(key string) string {
+	result, err := m.SignedBase64(key)
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+/*
+	URL Query
+	------------------------------------------------
+*/
+
+// URLValues creates a url.Values object from an Obj. This
+// function requires that the wrapped object be a map[string]interface{}
+func (m Map) URLValues() url.Values {
+
+	vals := make(url.Values)
+
+	for k, v := range m {
+		//TODO: can this be done without sprintf?
+		vals.Set(k, fmt.Sprintf("%v", v))
+	}
+
+	return vals
+}
+
+// URLQuery gets an encoded URL query representing the given
+// Obj. This function requires that the wrapped object be a
+// map[string]interface{}
+func (m Map) URLQuery() (string, error) {
+	return m.URLValues().Encode(), nil
+}

+ 94 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go

@@ -0,0 +1,94 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestConversionJSON(t *testing.T) {
+
+	jsonString := `{"name":"Mat"}`
+	o := MustFromJSON(jsonString)
+
+	result, err := o.JSON()
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, jsonString, result)
+	}
+
+	assert.Equal(t, jsonString, o.MustJSON())
+
+}
+
+func TestConversionJSONWithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustJSON()
+	})
+
+	_, err := o.JSON()
+
+	assert.Error(t, err)
+
+}
+
+func TestConversionBase64(t *testing.T) {
+
+	o := New(map[string]interface{}{"name": "Mat"})
+
+	result, err := o.Base64()
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", result)
+	}
+
+	assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", o.MustBase64())
+
+}
+
+func TestConversionBase64WithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustBase64()
+	})
+
+	_, err := o.Base64()
+
+	assert.Error(t, err)
+
+}
+
+func TestConversionSignedBase64(t *testing.T) {
+
+	o := New(map[string]interface{}{"name": "Mat"})
+
+	result, err := o.SignedBase64("key")
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", result)
+	}
+
+	assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", o.MustSignedBase64("key"))
+
+}
+
+func TestConversionSignedBase64WithError(t *testing.T) {
+
+	o := MSI()
+	o["test"] = func() {}
+
+	assert.Panics(t, func() {
+		o.MustSignedBase64("key")
+	})
+
+	_, err := o.SignedBase64("key")
+
+	assert.Error(t, err)
+
+}

+ 72 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/doc.go

@@ -0,0 +1,72 @@
+// objx - Go package for dealing with maps, slices, JSON and other data.
+//
+// Overview
+//
+// Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
+// a powerful `Get` method (among others) that allows you to easily and quickly get
+// access to data within the map, without having to worry too much about type assertions,
+// missing data, default values etc.
+//
+// Pattern
+//
+// Objx uses a preditable pattern to make access data from within `map[string]interface{}'s
+// easy.
+//
+// Call one of the `objx.` functions to create your `objx.Map` to get going:
+//
+//     m, err := objx.FromJSON(json)
+//
+// NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
+// the rest will be optimistic and try to figure things out without panicking.
+//
+// Use `Get` to access the value you're interested in.  You can use dot and array
+// notation too:
+//
+//     m.Get("places[0].latlng")
+//
+// Once you have saught the `Value` you're interested in, you can use the `Is*` methods
+// to determine its type.
+//
+//     if m.Get("code").IsStr() { /* ... */ }
+//
+// Or you can just assume the type, and use one of the strong type methods to
+// extract the real value:
+//
+//     m.Get("code").Int()
+//
+// If there's no value there (or if it's the wrong type) then a default value
+// will be returned, or you can be explicit about the default value.
+//
+//     Get("code").Int(-1)
+//
+// If you're dealing with a slice of data as a value, Objx provides many useful
+// methods for iterating, manipulating and selecting that data.  You can find out more
+// by exploring the index below.
+//
+// Reading data
+//
+// A simple example of how to use Objx:
+//
+//     // use MustFromJSON to make an objx.Map from some JSON
+//     m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
+//
+//     // get the details
+//     name := m.Get("name").Str()
+//     age := m.Get("age").Int()
+//
+//     // get their nickname (or use their name if they
+//     // don't have one)
+//     nickname := m.Get("nickname").Str(name)
+//
+// Ranging
+//
+// Since `objx.Map` is a `map[string]interface{}` you can treat it as such.  For
+// example, to `range` the data, do what you would expect:
+//
+//     m := objx.MustFromJSON(json)
+//     for key, value := range m {
+//
+//       /* ... do your magic ... */
+//
+//     }
+package objx

+ 98 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go

@@ -0,0 +1,98 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+var fixtures = []struct {
+	// name is the name of the fixture (used for reporting
+	// failures)
+	name string
+	// data is the JSON data to be worked on
+	data string
+	// get is the argument(s) to pass to Get
+	get interface{}
+	// output is the expected output
+	output interface{}
+}{
+	{
+		name:   "Simple get",
+		data:   `{"name": "Mat"}`,
+		get:    "name",
+		output: "Mat",
+	},
+	{
+		name:   "Get with dot notation",
+		data:   `{"address": {"city": "Boulder"}}`,
+		get:    "address.city",
+		output: "Boulder",
+	},
+	{
+		name:   "Deep get with dot notation",
+		data:   `{"one": {"two": {"three": {"four": "hello"}}}}`,
+		get:    "one.two.three.four",
+		output: "hello",
+	},
+	{
+		name:   "Get missing with dot notation",
+		data:   `{"one": {"two": {"three": {"four": "hello"}}}}`,
+		get:    "one.ten",
+		output: nil,
+	},
+	{
+		name:   "Get with array notation",
+		data:   `{"tags": ["one", "two", "three"]}`,
+		get:    "tags[1]",
+		output: "two",
+	},
+	{
+		name:   "Get with array and dot notation",
+		data:   `{"types": { "tags": ["one", "two", "three"]}}`,
+		get:    "types.tags[1]",
+		output: "two",
+	},
+	{
+		name:   "Get with array and dot notation - field after array",
+		data:   `{"tags": [{"name":"one"}, {"name":"two"}, {"name":"three"}]}`,
+		get:    "tags[1].name",
+		output: "two",
+	},
+	{
+		name:   "Complex get with array and dot notation",
+		data:   `{"tags": [{"list": [{"one":"pizza"}]}]}`,
+		get:    "tags[0].list[0].one",
+		output: "pizza",
+	},
+	{
+		name:   "Get field from within string should be nil",
+		data:   `{"name":"Tyler"}`,
+		get:    "name.something",
+		output: nil,
+	},
+	{
+		name:   "Get field from within string (using array accessor) should be nil",
+		data:   `{"numbers":["one", "two", "three"]}`,
+		get:    "numbers[0].nope",
+		output: nil,
+	},
+}
+
+func TestFixtures(t *testing.T) {
+
+	for _, fixture := range fixtures {
+
+		m := MustFromJSON(fixture.data)
+
+		// get the value
+		t.Logf("Running get fixture: \"%s\" (%v)", fixture.name, fixture)
+		value := m.Get(fixture.get.(string))
+
+		// make sure it matches
+		assert.Equal(t, fixture.output, value.data,
+			"Get fixture \"%s\" failed: %v", fixture.name, fixture,
+		)
+
+	}
+
+}

+ 222 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map.go

@@ -0,0 +1,222 @@
+package objx
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/url"
+	"strings"
+)
+
+// MSIConvertable is an interface that defines methods for converting your
+// custom types to a map[string]interface{} representation.
+type MSIConvertable interface {
+	// MSI gets a map[string]interface{} (msi) representing the
+	// object.
+	MSI() map[string]interface{}
+}
+
+// Map provides extended functionality for working with
+// untyped data, in particular map[string]interface (msi).
+type Map map[string]interface{}
+
+// Value returns the internal value instance
+func (m Map) Value() *Value {
+	return &Value{data: m}
+}
+
+// Nil represents a nil Map.
+var Nil Map = New(nil)
+
+// New creates a new Map containing the map[string]interface{} in the data argument.
+// If the data argument is not a map[string]interface, New attempts to call the
+// MSI() method on the MSIConvertable interface to create one.
+func New(data interface{}) Map {
+	if _, ok := data.(map[string]interface{}); !ok {
+		if converter, ok := data.(MSIConvertable); ok {
+			data = converter.MSI()
+		} else {
+			return nil
+		}
+	}
+	return Map(data.(map[string]interface{}))
+}
+
+// MSI creates a map[string]interface{} and puts it inside a new Map.
+//
+// The arguments follow a key, value pattern.
+//
+// Panics
+//
+// Panics if any key arugment is non-string or if there are an odd number of arguments.
+//
+// Example
+//
+// To easily create Maps:
+//
+//     m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
+//
+//     // creates an Map equivalent to
+//     m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
+func MSI(keyAndValuePairs ...interface{}) Map {
+
+	newMap := make(map[string]interface{})
+	keyAndValuePairsLen := len(keyAndValuePairs)
+
+	if keyAndValuePairsLen%2 != 0 {
+		panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
+	}
+
+	for i := 0; i < keyAndValuePairsLen; i = i + 2 {
+
+		key := keyAndValuePairs[i]
+		value := keyAndValuePairs[i+1]
+
+		// make sure the key is a string
+		keyString, keyStringOK := key.(string)
+		if !keyStringOK {
+			panic("objx: MSI must follow 'string, interface{}' pattern.  " + keyString + " is not a valid key.")
+		}
+
+		newMap[keyString] = value
+
+	}
+
+	return New(newMap)
+}
+
+// ****** Conversion Constructors
+
+// MustFromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Panics if the JSON is invalid.
+func MustFromJSON(jsonString string) Map {
+	o, err := FromJSON(jsonString)
+
+	if err != nil {
+		panic("objx: MustFromJSON failed with error: " + err.Error())
+	}
+
+	return o
+}
+
+// FromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Returns an error if the JSON is invalid.
+func FromJSON(jsonString string) (Map, error) {
+
+	var data interface{}
+	err := json.Unmarshal([]byte(jsonString), &data)
+
+	if err != nil {
+		return Nil, err
+	}
+
+	return New(data), nil
+
+}
+
+// FromBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by Base64
+func FromBase64(base64String string) (Map, error) {
+
+	decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
+
+	decoded, err := ioutil.ReadAll(decoder)
+	if err != nil {
+		return nil, err
+	}
+
+	return FromJSON(string(decoded))
+}
+
+// MustFromBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromBase64(base64String string) Map {
+
+	result, err := FromBase64(base64String)
+
+	if err != nil {
+		panic("objx: MustFromBase64 failed with error: " + err.Error())
+	}
+
+	return result
+}
+
+// FromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by SignedBase64
+func FromSignedBase64(base64String, key string) (Map, error) {
+	parts := strings.Split(base64String, SignatureSeparator)
+	if len(parts) != 2 {
+		return nil, errors.New("objx: Signed base64 string is malformed.")
+	}
+
+	sig := HashWithKey(parts[0], key)
+	if parts[1] != sig {
+		return nil, errors.New("objx: Signature for base64 data does not match.")
+	}
+
+	return FromBase64(parts[0])
+}
+
+// MustFromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromSignedBase64(base64String, key string) Map {
+
+	result, err := FromSignedBase64(base64String, key)
+
+	if err != nil {
+		panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
+	}
+
+	return result
+}
+
+// FromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+func FromURLQuery(query string) (Map, error) {
+
+	vals, err := url.ParseQuery(query)
+
+	if err != nil {
+		return nil, err
+	}
+
+	m := make(map[string]interface{})
+	for k, vals := range vals {
+		m[k] = vals[0]
+	}
+
+	return New(m), nil
+}
+
+// MustFromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+//
+// Panics if it encounters an error
+func MustFromURLQuery(query string) Map {
+
+	o, err := FromURLQuery(query)
+
+	if err != nil {
+		panic("objx: MustFromURLQuery failed with error: " + err.Error())
+	}
+
+	return o
+
+}

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_for_test.go

@@ -0,0 +1,10 @@
+package objx
+
+var TestMap map[string]interface{} = map[string]interface{}{
+	"name": "Tyler",
+	"address": map[string]interface{}{
+		"city":  "Salt Lake City",
+		"state": "UT",
+	},
+	"numbers": []interface{}{"one", "two", "three", "four", "five"},
+}

+ 147 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go

@@ -0,0 +1,147 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+type Convertable struct {
+	name string
+}
+
+func (c *Convertable) MSI() map[string]interface{} {
+	return map[string]interface{}{"name": c.name}
+}
+
+type Unconvertable struct {
+	name string
+}
+
+func TestMapCreation(t *testing.T) {
+
+	o := New(nil)
+	assert.Nil(t, o)
+
+	o = New("Tyler")
+	assert.Nil(t, o)
+
+	unconvertable := &Unconvertable{name: "Tyler"}
+	o = New(unconvertable)
+	assert.Nil(t, o)
+
+	convertable := &Convertable{name: "Tyler"}
+	o = New(convertable)
+	if assert.NotNil(t, convertable) {
+		assert.Equal(t, "Tyler", o["name"], "Tyler")
+	}
+
+	o = MSI()
+	if assert.NotNil(t, o) {
+		assert.NotNil(t, o)
+	}
+
+	o = MSI("name", "Tyler")
+	if assert.NotNil(t, o) {
+		if assert.NotNil(t, o) {
+			assert.Equal(t, o["name"], "Tyler")
+		}
+	}
+
+}
+
+func TestMapMustFromJSONWithError(t *testing.T) {
+
+	_, err := FromJSON(`"name":"Mat"}`)
+	assert.Error(t, err)
+
+}
+
+func TestMapFromJSON(t *testing.T) {
+
+	o := MustFromJSON(`{"name":"Mat"}`)
+
+	if assert.NotNil(t, o) {
+		if assert.NotNil(t, o) {
+			assert.Equal(t, "Mat", o["name"])
+		}
+	}
+
+}
+
+func TestMapFromJSONWithError(t *testing.T) {
+
+	var m Map
+
+	assert.Panics(t, func() {
+		m = MustFromJSON(`"name":"Mat"}`)
+	})
+
+	assert.Nil(t, m)
+
+}
+
+func TestMapFromBase64String(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWF0In0="
+
+	o, err := FromBase64(base64String)
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, o.Get("name").Str(), "Mat")
+	}
+
+	assert.Equal(t, MustFromBase64(base64String).Get("name").Str(), "Mat")
+
+}
+
+func TestMapFromBase64StringWithError(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWFasd0In0="
+
+	_, err := FromBase64(base64String)
+
+	assert.Error(t, err)
+
+	assert.Panics(t, func() {
+		MustFromBase64(base64String)
+	})
+
+}
+
+func TestMapFromSignedBase64String(t *testing.T) {
+
+	base64String := "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
+
+	o, err := FromSignedBase64(base64String, "key")
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, o.Get("name").Str(), "Mat")
+	}
+
+	assert.Equal(t, MustFromSignedBase64(base64String, "key").Get("name").Str(), "Mat")
+
+}
+
+func TestMapFromSignedBase64StringWithError(t *testing.T) {
+
+	base64String := "eyJuYW1lasdIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
+
+	_, err := FromSignedBase64(base64String, "key")
+
+	assert.Error(t, err)
+
+	assert.Panics(t, func() {
+		MustFromSignedBase64(base64String, "key")
+	})
+
+}
+
+func TestMapFromURLQuery(t *testing.T) {
+
+	m, err := FromURLQuery("name=tyler&state=UT")
+	if assert.NoError(t, err) && assert.NotNil(t, m) {
+		assert.Equal(t, "tyler", m.Get("name").Str())
+		assert.Equal(t, "UT", m.Get("state").Str())
+	}
+
+}

+ 81 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations.go

@@ -0,0 +1,81 @@
+package objx
+
+// Exclude returns a new Map with the keys in the specified []string
+// excluded.
+func (d Map) Exclude(exclude []string) Map {
+
+	excluded := make(Map)
+	for k, v := range d {
+		var shouldInclude bool = true
+		for _, toExclude := range exclude {
+			if k == toExclude {
+				shouldInclude = false
+				break
+			}
+		}
+		if shouldInclude {
+			excluded[k] = v
+		}
+	}
+
+	return excluded
+}
+
+// Copy creates a shallow copy of the Obj.
+func (m Map) Copy() Map {
+	copied := make(map[string]interface{})
+	for k, v := range m {
+		copied[k] = v
+	}
+	return New(copied)
+}
+
+// Merge blends the specified map with a copy of this map and returns the result.
+//
+// Keys that appear in both will be selected from the specified map.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) Merge(merge Map) Map {
+	return m.Copy().MergeHere(merge)
+}
+
+// Merge blends the specified map with this map and returns the current map.
+//
+// Keys that appear in both will be selected from the specified map.  The original map
+// will be modified. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) MergeHere(merge Map) Map {
+
+	for k, v := range merge {
+		m[k] = v
+	}
+
+	return m
+
+}
+
+// Transform builds a new Obj giving the transformer a chance
+// to change the keys and values as it goes. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
+	newMap := make(map[string]interface{})
+	for k, v := range m {
+		modifiedKey, modifiedVal := transformer(k, v)
+		newMap[modifiedKey] = modifiedVal
+	}
+	return New(newMap)
+}
+
+// TransformKeys builds a new map using the specified key mapping.
+//
+// Unspecified keys will be unaltered.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) TransformKeys(mapping map[string]string) Map {
+	return m.Transform(func(key string, value interface{}) (string, interface{}) {
+
+		if newKey, ok := mapping[key]; ok {
+			return newKey, value
+		}
+
+		return key, value
+	})
+}

+ 77 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/mutations_test.go

@@ -0,0 +1,77 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestExclude(t *testing.T) {
+
+	d := make(Map)
+	d["name"] = "Mat"
+	d["age"] = 29
+	d["secret"] = "ABC"
+
+	excluded := d.Exclude([]string{"secret"})
+
+	assert.Equal(t, d["name"], excluded["name"])
+	assert.Equal(t, d["age"], excluded["age"])
+	assert.False(t, excluded.Has("secret"), "secret should be excluded")
+
+}
+
+func TestCopy(t *testing.T) {
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	d1Obj := New(d1)
+	d2Obj := d1Obj.Copy()
+
+	d2Obj["name"] = "Mat"
+
+	assert.Equal(t, d1Obj.Get("name").Str(), "Tyler")
+	assert.Equal(t, d2Obj.Get("name").Str(), "Mat")
+
+}
+
+func TestMerge(t *testing.T) {
+
+	d := make(map[string]interface{})
+	d["name"] = "Mat"
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	dObj := New(d)
+	d1Obj := New(d1)
+
+	merged := dObj.Merge(d1Obj)
+
+	assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
+	assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
+	assert.Empty(t, dObj.Get("location").Str())
+
+}
+
+func TestMergeHere(t *testing.T) {
+
+	d := make(map[string]interface{})
+	d["name"] = "Mat"
+
+	d1 := make(map[string]interface{})
+	d1["name"] = "Tyler"
+	d1["location"] = "UT"
+
+	dObj := New(d)
+	d1Obj := New(d1)
+
+	merged := dObj.MergeHere(d1Obj)
+
+	assert.Equal(t, dObj, merged, "With MergeHere, it should return the first modified map")
+	assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
+	assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
+	assert.Equal(t, merged.Get("location").Str(), dObj.Get("location").Str())
+}

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security.go

@@ -0,0 +1,14 @@
+package objx
+
+import (
+	"crypto/sha1"
+	"encoding/hex"
+)
+
+// HashWithKey hashes the specified string using the security
+// key.
+func HashWithKey(data, key string) string {
+	hash := sha1.New()
+	hash.Write([]byte(data + ":" + key))
+	return hex.EncodeToString(hash.Sum(nil))
+}

+ 12 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/security_test.go

@@ -0,0 +1,12 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestHashWithKey(t *testing.T) {
+
+	assert.Equal(t, "0ce84d8d01f2c7b6e0882b784429c54d280ea2d9", HashWithKey("abc", "def"))
+
+}

+ 41 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/simple_example_test.go

@@ -0,0 +1,41 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestSimpleExample(t *testing.T) {
+
+	// build a map from a JSON object
+	o := MustFromJSON(`{"name":"Mat","foods":["indian","chinese"], "location":{"county":"hobbiton","city":"the shire"}}`)
+
+	// Map can be used as a straight map[string]interface{}
+	assert.Equal(t, o["name"], "Mat")
+
+	// Get an Value object
+	v := o.Get("name")
+	assert.Equal(t, v, &Value{data: "Mat"})
+
+	// Test the contained value
+	assert.False(t, v.IsInt())
+	assert.False(t, v.IsBool())
+	assert.True(t, v.IsStr())
+
+	// Get the contained value
+	assert.Equal(t, v.Str(), "Mat")
+
+	// Get a default value if the contained value is not of the expected type or does not exist
+	assert.Equal(t, 1, v.Int(1))
+
+	// Get a value by using array notation
+	assert.Equal(t, "indian", o.Get("foods[0]").Data())
+
+	// Set a value by using array notation
+	o.Set("foods[0]", "italian")
+	assert.Equal(t, "italian", o.Get("foods[0]").Str())
+
+	// Get a value by using dot notation
+	assert.Equal(t, "hobbiton", o.Get("location.county").Str())
+
+}

+ 17 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests.go

@@ -0,0 +1,17 @@
+package objx
+
+// Has gets whether there is something at the specified selector
+// or not.
+//
+// If m is nil, Has will always return false.
+func (m Map) Has(selector string) bool {
+	if m == nil {
+		return false
+	}
+	return !m.Get(selector).IsNil()
+}
+
+// IsNil gets whether the data is nil or not.
+func (v *Value) IsNil() bool {
+	return v == nil || v.data == nil
+}

+ 24 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/tests_test.go

@@ -0,0 +1,24 @@
+package objx
+
+import (
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestHas(t *testing.T) {
+
+	m := New(TestMap)
+
+	assert.True(t, m.Has("name"))
+	assert.True(t, m.Has("address.state"))
+	assert.True(t, m.Has("numbers[4]"))
+
+	assert.False(t, m.Has("address.state.nope"))
+	assert.False(t, m.Has("address.nope"))
+	assert.False(t, m.Has("nope"))
+	assert.False(t, m.Has("numbers[5]"))
+
+	m = nil
+	assert.False(t, m.Has("nothing"))
+
+}

+ 2881 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen.go

@@ -0,0 +1,2881 @@
+package objx
+
+/*
+	Inter (interface{} and []interface{})
+	--------------------------------------------------
+*/
+
+// Inter gets the value as a interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Inter(optionalDefault ...interface{}) interface{} {
+	if s, ok := v.data.(interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInter gets the value as a interface{}.
+//
+// Panics if the object is not a interface{}.
+func (v *Value) MustInter() interface{} {
+	return v.data.(interface{})
+}
+
+// InterSlice gets the value as a []interface{}, returns the optionalDefault
+// value or nil if the value is not a []interface{}.
+func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} {
+	if s, ok := v.data.([]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInterSlice gets the value as a []interface{}.
+//
+// Panics if the object is not a []interface{}.
+func (v *Value) MustInterSlice() []interface{} {
+	return v.data.([]interface{})
+}
+
+// IsInter gets whether the object contained is a interface{} or not.
+func (v *Value) IsInter() bool {
+	_, ok := v.data.(interface{})
+	return ok
+}
+
+// IsInterSlice gets whether the object contained is a []interface{} or not.
+func (v *Value) IsInterSlice() bool {
+	_, ok := v.data.([]interface{})
+	return ok
+}
+
+// EachInter calls the specified callback for each object
+// in the []interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInter(callback func(int, interface{}) bool) *Value {
+
+	for index, val := range v.MustInterSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInter uses the specified decider function to select items
+// from the []interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value {
+
+	var selected []interface{}
+
+	v.EachInter(func(index int, val interface{}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInter uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]interface{}.
+func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value {
+
+	groups := make(map[string][]interface{})
+
+	v.EachInter(func(index int, val interface{}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]interface{}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInter uses the specified function to replace each interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []interface{} containing the replaced items.
+func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value {
+
+	arr := v.MustInterSlice()
+	replaced := make([]interface{}, len(arr))
+
+	v.EachInter(func(index int, val interface{}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInter uses the specified collector function to collect a value
+// for each of the interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value {
+
+	arr := v.MustInterSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInter(func(index int, val interface{}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	MSI (map[string]interface{} and []map[string]interface{})
+	--------------------------------------------------
+*/
+
+// MSI gets the value as a map[string]interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
+	if s, ok := v.data.(map[string]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustMSI gets the value as a map[string]interface{}.
+//
+// Panics if the object is not a map[string]interface{}.
+func (v *Value) MustMSI() map[string]interface{} {
+	return v.data.(map[string]interface{})
+}
+
+// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
+// value or nil if the value is not a []map[string]interface{}.
+func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
+	if s, ok := v.data.([]map[string]interface{}); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustMSISlice gets the value as a []map[string]interface{}.
+//
+// Panics if the object is not a []map[string]interface{}.
+func (v *Value) MustMSISlice() []map[string]interface{} {
+	return v.data.([]map[string]interface{})
+}
+
+// IsMSI gets whether the object contained is a map[string]interface{} or not.
+func (v *Value) IsMSI() bool {
+	_, ok := v.data.(map[string]interface{})
+	return ok
+}
+
+// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
+func (v *Value) IsMSISlice() bool {
+	_, ok := v.data.([]map[string]interface{})
+	return ok
+}
+
+// EachMSI calls the specified callback for each object
+// in the []map[string]interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
+
+	for index, val := range v.MustMSISlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereMSI uses the specified decider function to select items
+// from the []map[string]interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
+
+	var selected []map[string]interface{}
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupMSI uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]map[string]interface{}.
+func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
+
+	groups := make(map[string][]map[string]interface{})
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]map[string]interface{}, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceMSI uses the specified function to replace each map[string]interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []map[string]interface{} containing the replaced items.
+func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
+
+	arr := v.MustMSISlice()
+	replaced := make([]map[string]interface{}, len(arr))
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectMSI uses the specified collector function to collect a value
+// for each of the map[string]interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
+
+	arr := v.MustMSISlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachMSI(func(index int, val map[string]interface{}) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	ObjxMap ((Map) and [](Map))
+	--------------------------------------------------
+*/
+
+// ObjxMap gets the value as a (Map), returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
+	if s, ok := v.data.((Map)); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return New(nil)
+}
+
+// MustObjxMap gets the value as a (Map).
+//
+// Panics if the object is not a (Map).
+func (v *Value) MustObjxMap() Map {
+	return v.data.((Map))
+}
+
+// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
+// value or nil if the value is not a [](Map).
+func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
+	if s, ok := v.data.([](Map)); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustObjxMapSlice gets the value as a [](Map).
+//
+// Panics if the object is not a [](Map).
+func (v *Value) MustObjxMapSlice() [](Map) {
+	return v.data.([](Map))
+}
+
+// IsObjxMap gets whether the object contained is a (Map) or not.
+func (v *Value) IsObjxMap() bool {
+	_, ok := v.data.((Map))
+	return ok
+}
+
+// IsObjxMapSlice gets whether the object contained is a [](Map) or not.
+func (v *Value) IsObjxMapSlice() bool {
+	_, ok := v.data.([](Map))
+	return ok
+}
+
+// EachObjxMap calls the specified callback for each object
+// in the [](Map).
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
+
+	for index, val := range v.MustObjxMapSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereObjxMap uses the specified decider function to select items
+// from the [](Map).  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
+
+	var selected [](Map)
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupObjxMap uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][](Map).
+func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
+
+	groups := make(map[string][](Map))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([](Map), 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceObjxMap uses the specified function to replace each (Map)s
+// by iterating each item.  The data in the returned result will be a
+// [](Map) containing the replaced items.
+func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
+
+	arr := v.MustObjxMapSlice()
+	replaced := make([](Map), len(arr))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectObjxMap uses the specified collector function to collect a value
+// for each of the (Map)s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
+
+	arr := v.MustObjxMapSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachObjxMap(func(index int, val Map) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Bool (bool and []bool)
+	--------------------------------------------------
+*/
+
+// Bool gets the value as a bool, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Bool(optionalDefault ...bool) bool {
+	if s, ok := v.data.(bool); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return false
+}
+
+// MustBool gets the value as a bool.
+//
+// Panics if the object is not a bool.
+func (v *Value) MustBool() bool {
+	return v.data.(bool)
+}
+
+// BoolSlice gets the value as a []bool, returns the optionalDefault
+// value or nil if the value is not a []bool.
+func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool {
+	if s, ok := v.data.([]bool); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustBoolSlice gets the value as a []bool.
+//
+// Panics if the object is not a []bool.
+func (v *Value) MustBoolSlice() []bool {
+	return v.data.([]bool)
+}
+
+// IsBool gets whether the object contained is a bool or not.
+func (v *Value) IsBool() bool {
+	_, ok := v.data.(bool)
+	return ok
+}
+
+// IsBoolSlice gets whether the object contained is a []bool or not.
+func (v *Value) IsBoolSlice() bool {
+	_, ok := v.data.([]bool)
+	return ok
+}
+
+// EachBool calls the specified callback for each object
+// in the []bool.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachBool(callback func(int, bool) bool) *Value {
+
+	for index, val := range v.MustBoolSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereBool uses the specified decider function to select items
+// from the []bool.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereBool(decider func(int, bool) bool) *Value {
+
+	var selected []bool
+
+	v.EachBool(func(index int, val bool) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupBool uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]bool.
+func (v *Value) GroupBool(grouper func(int, bool) string) *Value {
+
+	groups := make(map[string][]bool)
+
+	v.EachBool(func(index int, val bool) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]bool, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceBool uses the specified function to replace each bools
+// by iterating each item.  The data in the returned result will be a
+// []bool containing the replaced items.
+func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value {
+
+	arr := v.MustBoolSlice()
+	replaced := make([]bool, len(arr))
+
+	v.EachBool(func(index int, val bool) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectBool uses the specified collector function to collect a value
+// for each of the bools in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value {
+
+	arr := v.MustBoolSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachBool(func(index int, val bool) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Str (string and []string)
+	--------------------------------------------------
+*/
+
+// Str gets the value as a string, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Str(optionalDefault ...string) string {
+	if s, ok := v.data.(string); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return ""
+}
+
+// MustStr gets the value as a string.
+//
+// Panics if the object is not a string.
+func (v *Value) MustStr() string {
+	return v.data.(string)
+}
+
+// StrSlice gets the value as a []string, returns the optionalDefault
+// value or nil if the value is not a []string.
+func (v *Value) StrSlice(optionalDefault ...[]string) []string {
+	if s, ok := v.data.([]string); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustStrSlice gets the value as a []string.
+//
+// Panics if the object is not a []string.
+func (v *Value) MustStrSlice() []string {
+	return v.data.([]string)
+}
+
+// IsStr gets whether the object contained is a string or not.
+func (v *Value) IsStr() bool {
+	_, ok := v.data.(string)
+	return ok
+}
+
+// IsStrSlice gets whether the object contained is a []string or not.
+func (v *Value) IsStrSlice() bool {
+	_, ok := v.data.([]string)
+	return ok
+}
+
+// EachStr calls the specified callback for each object
+// in the []string.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachStr(callback func(int, string) bool) *Value {
+
+	for index, val := range v.MustStrSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereStr uses the specified decider function to select items
+// from the []string.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereStr(decider func(int, string) bool) *Value {
+
+	var selected []string
+
+	v.EachStr(func(index int, val string) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupStr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]string.
+func (v *Value) GroupStr(grouper func(int, string) string) *Value {
+
+	groups := make(map[string][]string)
+
+	v.EachStr(func(index int, val string) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]string, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceStr uses the specified function to replace each strings
+// by iterating each item.  The data in the returned result will be a
+// []string containing the replaced items.
+func (v *Value) ReplaceStr(replacer func(int, string) string) *Value {
+
+	arr := v.MustStrSlice()
+	replaced := make([]string, len(arr))
+
+	v.EachStr(func(index int, val string) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectStr uses the specified collector function to collect a value
+// for each of the strings in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectStr(collector func(int, string) interface{}) *Value {
+
+	arr := v.MustStrSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachStr(func(index int, val string) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int (int and []int)
+	--------------------------------------------------
+*/
+
+// Int gets the value as a int, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int(optionalDefault ...int) int {
+	if s, ok := v.data.(int); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt gets the value as a int.
+//
+// Panics if the object is not a int.
+func (v *Value) MustInt() int {
+	return v.data.(int)
+}
+
+// IntSlice gets the value as a []int, returns the optionalDefault
+// value or nil if the value is not a []int.
+func (v *Value) IntSlice(optionalDefault ...[]int) []int {
+	if s, ok := v.data.([]int); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustIntSlice gets the value as a []int.
+//
+// Panics if the object is not a []int.
+func (v *Value) MustIntSlice() []int {
+	return v.data.([]int)
+}
+
+// IsInt gets whether the object contained is a int or not.
+func (v *Value) IsInt() bool {
+	_, ok := v.data.(int)
+	return ok
+}
+
+// IsIntSlice gets whether the object contained is a []int or not.
+func (v *Value) IsIntSlice() bool {
+	_, ok := v.data.([]int)
+	return ok
+}
+
+// EachInt calls the specified callback for each object
+// in the []int.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt(callback func(int, int) bool) *Value {
+
+	for index, val := range v.MustIntSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt uses the specified decider function to select items
+// from the []int.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt(decider func(int, int) bool) *Value {
+
+	var selected []int
+
+	v.EachInt(func(index int, val int) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int.
+func (v *Value) GroupInt(grouper func(int, int) string) *Value {
+
+	groups := make(map[string][]int)
+
+	v.EachInt(func(index int, val int) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt uses the specified function to replace each ints
+// by iterating each item.  The data in the returned result will be a
+// []int containing the replaced items.
+func (v *Value) ReplaceInt(replacer func(int, int) int) *Value {
+
+	arr := v.MustIntSlice()
+	replaced := make([]int, len(arr))
+
+	v.EachInt(func(index int, val int) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt uses the specified collector function to collect a value
+// for each of the ints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt(collector func(int, int) interface{}) *Value {
+
+	arr := v.MustIntSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt(func(index int, val int) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int8 (int8 and []int8)
+	--------------------------------------------------
+*/
+
+// Int8 gets the value as a int8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int8(optionalDefault ...int8) int8 {
+	if s, ok := v.data.(int8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt8 gets the value as a int8.
+//
+// Panics if the object is not a int8.
+func (v *Value) MustInt8() int8 {
+	return v.data.(int8)
+}
+
+// Int8Slice gets the value as a []int8, returns the optionalDefault
+// value or nil if the value is not a []int8.
+func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 {
+	if s, ok := v.data.([]int8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt8Slice gets the value as a []int8.
+//
+// Panics if the object is not a []int8.
+func (v *Value) MustInt8Slice() []int8 {
+	return v.data.([]int8)
+}
+
+// IsInt8 gets whether the object contained is a int8 or not.
+func (v *Value) IsInt8() bool {
+	_, ok := v.data.(int8)
+	return ok
+}
+
+// IsInt8Slice gets whether the object contained is a []int8 or not.
+func (v *Value) IsInt8Slice() bool {
+	_, ok := v.data.([]int8)
+	return ok
+}
+
+// EachInt8 calls the specified callback for each object
+// in the []int8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt8(callback func(int, int8) bool) *Value {
+
+	for index, val := range v.MustInt8Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt8 uses the specified decider function to select items
+// from the []int8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt8(decider func(int, int8) bool) *Value {
+
+	var selected []int8
+
+	v.EachInt8(func(index int, val int8) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int8.
+func (v *Value) GroupInt8(grouper func(int, int8) string) *Value {
+
+	groups := make(map[string][]int8)
+
+	v.EachInt8(func(index int, val int8) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int8, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt8 uses the specified function to replace each int8s
+// by iterating each item.  The data in the returned result will be a
+// []int8 containing the replaced items.
+func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value {
+
+	arr := v.MustInt8Slice()
+	replaced := make([]int8, len(arr))
+
+	v.EachInt8(func(index int, val int8) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt8 uses the specified collector function to collect a value
+// for each of the int8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value {
+
+	arr := v.MustInt8Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt8(func(index int, val int8) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int16 (int16 and []int16)
+	--------------------------------------------------
+*/
+
+// Int16 gets the value as a int16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int16(optionalDefault ...int16) int16 {
+	if s, ok := v.data.(int16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt16 gets the value as a int16.
+//
+// Panics if the object is not a int16.
+func (v *Value) MustInt16() int16 {
+	return v.data.(int16)
+}
+
+// Int16Slice gets the value as a []int16, returns the optionalDefault
+// value or nil if the value is not a []int16.
+func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 {
+	if s, ok := v.data.([]int16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt16Slice gets the value as a []int16.
+//
+// Panics if the object is not a []int16.
+func (v *Value) MustInt16Slice() []int16 {
+	return v.data.([]int16)
+}
+
+// IsInt16 gets whether the object contained is a int16 or not.
+func (v *Value) IsInt16() bool {
+	_, ok := v.data.(int16)
+	return ok
+}
+
+// IsInt16Slice gets whether the object contained is a []int16 or not.
+func (v *Value) IsInt16Slice() bool {
+	_, ok := v.data.([]int16)
+	return ok
+}
+
+// EachInt16 calls the specified callback for each object
+// in the []int16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt16(callback func(int, int16) bool) *Value {
+
+	for index, val := range v.MustInt16Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt16 uses the specified decider function to select items
+// from the []int16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt16(decider func(int, int16) bool) *Value {
+
+	var selected []int16
+
+	v.EachInt16(func(index int, val int16) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int16.
+func (v *Value) GroupInt16(grouper func(int, int16) string) *Value {
+
+	groups := make(map[string][]int16)
+
+	v.EachInt16(func(index int, val int16) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int16, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt16 uses the specified function to replace each int16s
+// by iterating each item.  The data in the returned result will be a
+// []int16 containing the replaced items.
+func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value {
+
+	arr := v.MustInt16Slice()
+	replaced := make([]int16, len(arr))
+
+	v.EachInt16(func(index int, val int16) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt16 uses the specified collector function to collect a value
+// for each of the int16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value {
+
+	arr := v.MustInt16Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt16(func(index int, val int16) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int32 (int32 and []int32)
+	--------------------------------------------------
+*/
+
+// Int32 gets the value as a int32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int32(optionalDefault ...int32) int32 {
+	if s, ok := v.data.(int32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt32 gets the value as a int32.
+//
+// Panics if the object is not a int32.
+func (v *Value) MustInt32() int32 {
+	return v.data.(int32)
+}
+
+// Int32Slice gets the value as a []int32, returns the optionalDefault
+// value or nil if the value is not a []int32.
+func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 {
+	if s, ok := v.data.([]int32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt32Slice gets the value as a []int32.
+//
+// Panics if the object is not a []int32.
+func (v *Value) MustInt32Slice() []int32 {
+	return v.data.([]int32)
+}
+
+// IsInt32 gets whether the object contained is a int32 or not.
+func (v *Value) IsInt32() bool {
+	_, ok := v.data.(int32)
+	return ok
+}
+
+// IsInt32Slice gets whether the object contained is a []int32 or not.
+func (v *Value) IsInt32Slice() bool {
+	_, ok := v.data.([]int32)
+	return ok
+}
+
+// EachInt32 calls the specified callback for each object
+// in the []int32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt32(callback func(int, int32) bool) *Value {
+
+	for index, val := range v.MustInt32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt32 uses the specified decider function to select items
+// from the []int32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt32(decider func(int, int32) bool) *Value {
+
+	var selected []int32
+
+	v.EachInt32(func(index int, val int32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int32.
+func (v *Value) GroupInt32(grouper func(int, int32) string) *Value {
+
+	groups := make(map[string][]int32)
+
+	v.EachInt32(func(index int, val int32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt32 uses the specified function to replace each int32s
+// by iterating each item.  The data in the returned result will be a
+// []int32 containing the replaced items.
+func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value {
+
+	arr := v.MustInt32Slice()
+	replaced := make([]int32, len(arr))
+
+	v.EachInt32(func(index int, val int32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt32 uses the specified collector function to collect a value
+// for each of the int32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value {
+
+	arr := v.MustInt32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt32(func(index int, val int32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Int64 (int64 and []int64)
+	--------------------------------------------------
+*/
+
+// Int64 gets the value as a int64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int64(optionalDefault ...int64) int64 {
+	if s, ok := v.data.(int64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustInt64 gets the value as a int64.
+//
+// Panics if the object is not a int64.
+func (v *Value) MustInt64() int64 {
+	return v.data.(int64)
+}
+
+// Int64Slice gets the value as a []int64, returns the optionalDefault
+// value or nil if the value is not a []int64.
+func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 {
+	if s, ok := v.data.([]int64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustInt64Slice gets the value as a []int64.
+//
+// Panics if the object is not a []int64.
+func (v *Value) MustInt64Slice() []int64 {
+	return v.data.([]int64)
+}
+
+// IsInt64 gets whether the object contained is a int64 or not.
+func (v *Value) IsInt64() bool {
+	_, ok := v.data.(int64)
+	return ok
+}
+
+// IsInt64Slice gets whether the object contained is a []int64 or not.
+func (v *Value) IsInt64Slice() bool {
+	_, ok := v.data.([]int64)
+	return ok
+}
+
+// EachInt64 calls the specified callback for each object
+// in the []int64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt64(callback func(int, int64) bool) *Value {
+
+	for index, val := range v.MustInt64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereInt64 uses the specified decider function to select items
+// from the []int64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt64(decider func(int, int64) bool) *Value {
+
+	var selected []int64
+
+	v.EachInt64(func(index int, val int64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupInt64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int64.
+func (v *Value) GroupInt64(grouper func(int, int64) string) *Value {
+
+	groups := make(map[string][]int64)
+
+	v.EachInt64(func(index int, val int64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]int64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceInt64 uses the specified function to replace each int64s
+// by iterating each item.  The data in the returned result will be a
+// []int64 containing the replaced items.
+func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value {
+
+	arr := v.MustInt64Slice()
+	replaced := make([]int64, len(arr))
+
+	v.EachInt64(func(index int, val int64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectInt64 uses the specified collector function to collect a value
+// for each of the int64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value {
+
+	arr := v.MustInt64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachInt64(func(index int, val int64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint (uint and []uint)
+	--------------------------------------------------
+*/
+
+// Uint gets the value as a uint, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint(optionalDefault ...uint) uint {
+	if s, ok := v.data.(uint); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint gets the value as a uint.
+//
+// Panics if the object is not a uint.
+func (v *Value) MustUint() uint {
+	return v.data.(uint)
+}
+
+// UintSlice gets the value as a []uint, returns the optionalDefault
+// value or nil if the value is not a []uint.
+func (v *Value) UintSlice(optionalDefault ...[]uint) []uint {
+	if s, ok := v.data.([]uint); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUintSlice gets the value as a []uint.
+//
+// Panics if the object is not a []uint.
+func (v *Value) MustUintSlice() []uint {
+	return v.data.([]uint)
+}
+
+// IsUint gets whether the object contained is a uint or not.
+func (v *Value) IsUint() bool {
+	_, ok := v.data.(uint)
+	return ok
+}
+
+// IsUintSlice gets whether the object contained is a []uint or not.
+func (v *Value) IsUintSlice() bool {
+	_, ok := v.data.([]uint)
+	return ok
+}
+
+// EachUint calls the specified callback for each object
+// in the []uint.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint(callback func(int, uint) bool) *Value {
+
+	for index, val := range v.MustUintSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint uses the specified decider function to select items
+// from the []uint.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint(decider func(int, uint) bool) *Value {
+
+	var selected []uint
+
+	v.EachUint(func(index int, val uint) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint.
+func (v *Value) GroupUint(grouper func(int, uint) string) *Value {
+
+	groups := make(map[string][]uint)
+
+	v.EachUint(func(index int, val uint) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint uses the specified function to replace each uints
+// by iterating each item.  The data in the returned result will be a
+// []uint containing the replaced items.
+func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value {
+
+	arr := v.MustUintSlice()
+	replaced := make([]uint, len(arr))
+
+	v.EachUint(func(index int, val uint) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint uses the specified collector function to collect a value
+// for each of the uints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value {
+
+	arr := v.MustUintSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint(func(index int, val uint) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint8 (uint8 and []uint8)
+	--------------------------------------------------
+*/
+
+// Uint8 gets the value as a uint8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint8(optionalDefault ...uint8) uint8 {
+	if s, ok := v.data.(uint8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint8 gets the value as a uint8.
+//
+// Panics if the object is not a uint8.
+func (v *Value) MustUint8() uint8 {
+	return v.data.(uint8)
+}
+
+// Uint8Slice gets the value as a []uint8, returns the optionalDefault
+// value or nil if the value is not a []uint8.
+func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 {
+	if s, ok := v.data.([]uint8); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint8Slice gets the value as a []uint8.
+//
+// Panics if the object is not a []uint8.
+func (v *Value) MustUint8Slice() []uint8 {
+	return v.data.([]uint8)
+}
+
+// IsUint8 gets whether the object contained is a uint8 or not.
+func (v *Value) IsUint8() bool {
+	_, ok := v.data.(uint8)
+	return ok
+}
+
+// IsUint8Slice gets whether the object contained is a []uint8 or not.
+func (v *Value) IsUint8Slice() bool {
+	_, ok := v.data.([]uint8)
+	return ok
+}
+
+// EachUint8 calls the specified callback for each object
+// in the []uint8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint8(callback func(int, uint8) bool) *Value {
+
+	for index, val := range v.MustUint8Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint8 uses the specified decider function to select items
+// from the []uint8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value {
+
+	var selected []uint8
+
+	v.EachUint8(func(index int, val uint8) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint8.
+func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value {
+
+	groups := make(map[string][]uint8)
+
+	v.EachUint8(func(index int, val uint8) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint8, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint8 uses the specified function to replace each uint8s
+// by iterating each item.  The data in the returned result will be a
+// []uint8 containing the replaced items.
+func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value {
+
+	arr := v.MustUint8Slice()
+	replaced := make([]uint8, len(arr))
+
+	v.EachUint8(func(index int, val uint8) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint8 uses the specified collector function to collect a value
+// for each of the uint8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value {
+
+	arr := v.MustUint8Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint8(func(index int, val uint8) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint16 (uint16 and []uint16)
+	--------------------------------------------------
+*/
+
+// Uint16 gets the value as a uint16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint16(optionalDefault ...uint16) uint16 {
+	if s, ok := v.data.(uint16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint16 gets the value as a uint16.
+//
+// Panics if the object is not a uint16.
+func (v *Value) MustUint16() uint16 {
+	return v.data.(uint16)
+}
+
+// Uint16Slice gets the value as a []uint16, returns the optionalDefault
+// value or nil if the value is not a []uint16.
+func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 {
+	if s, ok := v.data.([]uint16); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint16Slice gets the value as a []uint16.
+//
+// Panics if the object is not a []uint16.
+func (v *Value) MustUint16Slice() []uint16 {
+	return v.data.([]uint16)
+}
+
+// IsUint16 gets whether the object contained is a uint16 or not.
+func (v *Value) IsUint16() bool {
+	_, ok := v.data.(uint16)
+	return ok
+}
+
+// IsUint16Slice gets whether the object contained is a []uint16 or not.
+func (v *Value) IsUint16Slice() bool {
+	_, ok := v.data.([]uint16)
+	return ok
+}
+
+// EachUint16 calls the specified callback for each object
+// in the []uint16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint16(callback func(int, uint16) bool) *Value {
+
+	for index, val := range v.MustUint16Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint16 uses the specified decider function to select items
+// from the []uint16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value {
+
+	var selected []uint16
+
+	v.EachUint16(func(index int, val uint16) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint16.
+func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value {
+
+	groups := make(map[string][]uint16)
+
+	v.EachUint16(func(index int, val uint16) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint16, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint16 uses the specified function to replace each uint16s
+// by iterating each item.  The data in the returned result will be a
+// []uint16 containing the replaced items.
+func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value {
+
+	arr := v.MustUint16Slice()
+	replaced := make([]uint16, len(arr))
+
+	v.EachUint16(func(index int, val uint16) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint16 uses the specified collector function to collect a value
+// for each of the uint16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value {
+
+	arr := v.MustUint16Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint16(func(index int, val uint16) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint32 (uint32 and []uint32)
+	--------------------------------------------------
+*/
+
+// Uint32 gets the value as a uint32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint32(optionalDefault ...uint32) uint32 {
+	if s, ok := v.data.(uint32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint32 gets the value as a uint32.
+//
+// Panics if the object is not a uint32.
+func (v *Value) MustUint32() uint32 {
+	return v.data.(uint32)
+}
+
+// Uint32Slice gets the value as a []uint32, returns the optionalDefault
+// value or nil if the value is not a []uint32.
+func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 {
+	if s, ok := v.data.([]uint32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint32Slice gets the value as a []uint32.
+//
+// Panics if the object is not a []uint32.
+func (v *Value) MustUint32Slice() []uint32 {
+	return v.data.([]uint32)
+}
+
+// IsUint32 gets whether the object contained is a uint32 or not.
+func (v *Value) IsUint32() bool {
+	_, ok := v.data.(uint32)
+	return ok
+}
+
+// IsUint32Slice gets whether the object contained is a []uint32 or not.
+func (v *Value) IsUint32Slice() bool {
+	_, ok := v.data.([]uint32)
+	return ok
+}
+
+// EachUint32 calls the specified callback for each object
+// in the []uint32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint32(callback func(int, uint32) bool) *Value {
+
+	for index, val := range v.MustUint32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint32 uses the specified decider function to select items
+// from the []uint32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value {
+
+	var selected []uint32
+
+	v.EachUint32(func(index int, val uint32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint32.
+func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value {
+
+	groups := make(map[string][]uint32)
+
+	v.EachUint32(func(index int, val uint32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint32 uses the specified function to replace each uint32s
+// by iterating each item.  The data in the returned result will be a
+// []uint32 containing the replaced items.
+func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value {
+
+	arr := v.MustUint32Slice()
+	replaced := make([]uint32, len(arr))
+
+	v.EachUint32(func(index int, val uint32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint32 uses the specified collector function to collect a value
+// for each of the uint32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value {
+
+	arr := v.MustUint32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint32(func(index int, val uint32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uint64 (uint64 and []uint64)
+	--------------------------------------------------
+*/
+
+// Uint64 gets the value as a uint64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint64(optionalDefault ...uint64) uint64 {
+	if s, ok := v.data.(uint64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUint64 gets the value as a uint64.
+//
+// Panics if the object is not a uint64.
+func (v *Value) MustUint64() uint64 {
+	return v.data.(uint64)
+}
+
+// Uint64Slice gets the value as a []uint64, returns the optionalDefault
+// value or nil if the value is not a []uint64.
+func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 {
+	if s, ok := v.data.([]uint64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUint64Slice gets the value as a []uint64.
+//
+// Panics if the object is not a []uint64.
+func (v *Value) MustUint64Slice() []uint64 {
+	return v.data.([]uint64)
+}
+
+// IsUint64 gets whether the object contained is a uint64 or not.
+func (v *Value) IsUint64() bool {
+	_, ok := v.data.(uint64)
+	return ok
+}
+
+// IsUint64Slice gets whether the object contained is a []uint64 or not.
+func (v *Value) IsUint64Slice() bool {
+	_, ok := v.data.([]uint64)
+	return ok
+}
+
+// EachUint64 calls the specified callback for each object
+// in the []uint64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint64(callback func(int, uint64) bool) *Value {
+
+	for index, val := range v.MustUint64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUint64 uses the specified decider function to select items
+// from the []uint64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value {
+
+	var selected []uint64
+
+	v.EachUint64(func(index int, val uint64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUint64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint64.
+func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value {
+
+	groups := make(map[string][]uint64)
+
+	v.EachUint64(func(index int, val uint64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uint64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUint64 uses the specified function to replace each uint64s
+// by iterating each item.  The data in the returned result will be a
+// []uint64 containing the replaced items.
+func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value {
+
+	arr := v.MustUint64Slice()
+	replaced := make([]uint64, len(arr))
+
+	v.EachUint64(func(index int, val uint64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUint64 uses the specified collector function to collect a value
+// for each of the uint64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value {
+
+	arr := v.MustUint64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUint64(func(index int, val uint64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Uintptr (uintptr and []uintptr)
+	--------------------------------------------------
+*/
+
+// Uintptr gets the value as a uintptr, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr {
+	if s, ok := v.data.(uintptr); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustUintptr gets the value as a uintptr.
+//
+// Panics if the object is not a uintptr.
+func (v *Value) MustUintptr() uintptr {
+	return v.data.(uintptr)
+}
+
+// UintptrSlice gets the value as a []uintptr, returns the optionalDefault
+// value or nil if the value is not a []uintptr.
+func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr {
+	if s, ok := v.data.([]uintptr); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustUintptrSlice gets the value as a []uintptr.
+//
+// Panics if the object is not a []uintptr.
+func (v *Value) MustUintptrSlice() []uintptr {
+	return v.data.([]uintptr)
+}
+
+// IsUintptr gets whether the object contained is a uintptr or not.
+func (v *Value) IsUintptr() bool {
+	_, ok := v.data.(uintptr)
+	return ok
+}
+
+// IsUintptrSlice gets whether the object contained is a []uintptr or not.
+func (v *Value) IsUintptrSlice() bool {
+	_, ok := v.data.([]uintptr)
+	return ok
+}
+
+// EachUintptr calls the specified callback for each object
+// in the []uintptr.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value {
+
+	for index, val := range v.MustUintptrSlice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereUintptr uses the specified decider function to select items
+// from the []uintptr.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value {
+
+	var selected []uintptr
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupUintptr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uintptr.
+func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value {
+
+	groups := make(map[string][]uintptr)
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]uintptr, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceUintptr uses the specified function to replace each uintptrs
+// by iterating each item.  The data in the returned result will be a
+// []uintptr containing the replaced items.
+func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value {
+
+	arr := v.MustUintptrSlice()
+	replaced := make([]uintptr, len(arr))
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectUintptr uses the specified collector function to collect a value
+// for each of the uintptrs in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value {
+
+	arr := v.MustUintptrSlice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachUintptr(func(index int, val uintptr) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Float32 (float32 and []float32)
+	--------------------------------------------------
+*/
+
+// Float32 gets the value as a float32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float32(optionalDefault ...float32) float32 {
+	if s, ok := v.data.(float32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustFloat32 gets the value as a float32.
+//
+// Panics if the object is not a float32.
+func (v *Value) MustFloat32() float32 {
+	return v.data.(float32)
+}
+
+// Float32Slice gets the value as a []float32, returns the optionalDefault
+// value or nil if the value is not a []float32.
+func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 {
+	if s, ok := v.data.([]float32); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustFloat32Slice gets the value as a []float32.
+//
+// Panics if the object is not a []float32.
+func (v *Value) MustFloat32Slice() []float32 {
+	return v.data.([]float32)
+}
+
+// IsFloat32 gets whether the object contained is a float32 or not.
+func (v *Value) IsFloat32() bool {
+	_, ok := v.data.(float32)
+	return ok
+}
+
+// IsFloat32Slice gets whether the object contained is a []float32 or not.
+func (v *Value) IsFloat32Slice() bool {
+	_, ok := v.data.([]float32)
+	return ok
+}
+
+// EachFloat32 calls the specified callback for each object
+// in the []float32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat32(callback func(int, float32) bool) *Value {
+
+	for index, val := range v.MustFloat32Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereFloat32 uses the specified decider function to select items
+// from the []float32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value {
+
+	var selected []float32
+
+	v.EachFloat32(func(index int, val float32) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupFloat32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float32.
+func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value {
+
+	groups := make(map[string][]float32)
+
+	v.EachFloat32(func(index int, val float32) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]float32, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceFloat32 uses the specified function to replace each float32s
+// by iterating each item.  The data in the returned result will be a
+// []float32 containing the replaced items.
+func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value {
+
+	arr := v.MustFloat32Slice()
+	replaced := make([]float32, len(arr))
+
+	v.EachFloat32(func(index int, val float32) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectFloat32 uses the specified collector function to collect a value
+// for each of the float32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value {
+
+	arr := v.MustFloat32Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachFloat32(func(index int, val float32) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Float64 (float64 and []float64)
+	--------------------------------------------------
+*/
+
+// Float64 gets the value as a float64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float64(optionalDefault ...float64) float64 {
+	if s, ok := v.data.(float64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustFloat64 gets the value as a float64.
+//
+// Panics if the object is not a float64.
+func (v *Value) MustFloat64() float64 {
+	return v.data.(float64)
+}
+
+// Float64Slice gets the value as a []float64, returns the optionalDefault
+// value or nil if the value is not a []float64.
+func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 {
+	if s, ok := v.data.([]float64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustFloat64Slice gets the value as a []float64.
+//
+// Panics if the object is not a []float64.
+func (v *Value) MustFloat64Slice() []float64 {
+	return v.data.([]float64)
+}
+
+// IsFloat64 gets whether the object contained is a float64 or not.
+func (v *Value) IsFloat64() bool {
+	_, ok := v.data.(float64)
+	return ok
+}
+
+// IsFloat64Slice gets whether the object contained is a []float64 or not.
+func (v *Value) IsFloat64Slice() bool {
+	_, ok := v.data.([]float64)
+	return ok
+}
+
+// EachFloat64 calls the specified callback for each object
+// in the []float64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat64(callback func(int, float64) bool) *Value {
+
+	for index, val := range v.MustFloat64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereFloat64 uses the specified decider function to select items
+// from the []float64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value {
+
+	var selected []float64
+
+	v.EachFloat64(func(index int, val float64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupFloat64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float64.
+func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value {
+
+	groups := make(map[string][]float64)
+
+	v.EachFloat64(func(index int, val float64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]float64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceFloat64 uses the specified function to replace each float64s
+// by iterating each item.  The data in the returned result will be a
+// []float64 containing the replaced items.
+func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value {
+
+	arr := v.MustFloat64Slice()
+	replaced := make([]float64, len(arr))
+
+	v.EachFloat64(func(index int, val float64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectFloat64 uses the specified collector function to collect a value
+// for each of the float64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value {
+
+	arr := v.MustFloat64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachFloat64(func(index int, val float64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Complex64 (complex64 and []complex64)
+	--------------------------------------------------
+*/
+
+// Complex64 gets the value as a complex64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex64(optionalDefault ...complex64) complex64 {
+	if s, ok := v.data.(complex64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustComplex64 gets the value as a complex64.
+//
+// Panics if the object is not a complex64.
+func (v *Value) MustComplex64() complex64 {
+	return v.data.(complex64)
+}
+
+// Complex64Slice gets the value as a []complex64, returns the optionalDefault
+// value or nil if the value is not a []complex64.
+func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 {
+	if s, ok := v.data.([]complex64); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustComplex64Slice gets the value as a []complex64.
+//
+// Panics if the object is not a []complex64.
+func (v *Value) MustComplex64Slice() []complex64 {
+	return v.data.([]complex64)
+}
+
+// IsComplex64 gets whether the object contained is a complex64 or not.
+func (v *Value) IsComplex64() bool {
+	_, ok := v.data.(complex64)
+	return ok
+}
+
+// IsComplex64Slice gets whether the object contained is a []complex64 or not.
+func (v *Value) IsComplex64Slice() bool {
+	_, ok := v.data.([]complex64)
+	return ok
+}
+
+// EachComplex64 calls the specified callback for each object
+// in the []complex64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value {
+
+	for index, val := range v.MustComplex64Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereComplex64 uses the specified decider function to select items
+// from the []complex64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value {
+
+	var selected []complex64
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupComplex64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex64.
+func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value {
+
+	groups := make(map[string][]complex64)
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]complex64, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceComplex64 uses the specified function to replace each complex64s
+// by iterating each item.  The data in the returned result will be a
+// []complex64 containing the replaced items.
+func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value {
+
+	arr := v.MustComplex64Slice()
+	replaced := make([]complex64, len(arr))
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectComplex64 uses the specified collector function to collect a value
+// for each of the complex64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value {
+
+	arr := v.MustComplex64Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachComplex64(func(index int, val complex64) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}
+
+/*
+	Complex128 (complex128 and []complex128)
+	--------------------------------------------------
+*/
+
+// Complex128 gets the value as a complex128, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex128(optionalDefault ...complex128) complex128 {
+	if s, ok := v.data.(complex128); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return 0
+}
+
+// MustComplex128 gets the value as a complex128.
+//
+// Panics if the object is not a complex128.
+func (v *Value) MustComplex128() complex128 {
+	return v.data.(complex128)
+}
+
+// Complex128Slice gets the value as a []complex128, returns the optionalDefault
+// value or nil if the value is not a []complex128.
+func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 {
+	if s, ok := v.data.([]complex128); ok {
+		return s
+	}
+	if len(optionalDefault) == 1 {
+		return optionalDefault[0]
+	}
+	return nil
+}
+
+// MustComplex128Slice gets the value as a []complex128.
+//
+// Panics if the object is not a []complex128.
+func (v *Value) MustComplex128Slice() []complex128 {
+	return v.data.([]complex128)
+}
+
+// IsComplex128 gets whether the object contained is a complex128 or not.
+func (v *Value) IsComplex128() bool {
+	_, ok := v.data.(complex128)
+	return ok
+}
+
+// IsComplex128Slice gets whether the object contained is a []complex128 or not.
+func (v *Value) IsComplex128Slice() bool {
+	_, ok := v.data.([]complex128)
+	return ok
+}
+
+// EachComplex128 calls the specified callback for each object
+// in the []complex128.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value {
+
+	for index, val := range v.MustComplex128Slice() {
+		carryon := callback(index, val)
+		if carryon == false {
+			break
+		}
+	}
+
+	return v
+
+}
+
+// WhereComplex128 uses the specified decider function to select items
+// from the []complex128.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value {
+
+	var selected []complex128
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		shouldSelect := decider(index, val)
+		if shouldSelect == false {
+			selected = append(selected, val)
+		}
+		return true
+	})
+
+	return &Value{data: selected}
+
+}
+
+// GroupComplex128 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex128.
+func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value {
+
+	groups := make(map[string][]complex128)
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		group := grouper(index, val)
+		if _, ok := groups[group]; !ok {
+			groups[group] = make([]complex128, 0)
+		}
+		groups[group] = append(groups[group], val)
+		return true
+	})
+
+	return &Value{data: groups}
+
+}
+
+// ReplaceComplex128 uses the specified function to replace each complex128s
+// by iterating each item.  The data in the returned result will be a
+// []complex128 containing the replaced items.
+func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value {
+
+	arr := v.MustComplex128Slice()
+	replaced := make([]complex128, len(arr))
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		replaced[index] = replacer(index, val)
+		return true
+	})
+
+	return &Value{data: replaced}
+
+}
+
+// CollectComplex128 uses the specified collector function to collect a value
+// for each of the complex128s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value {
+
+	arr := v.MustComplex128Slice()
+	collected := make([]interface{}, len(arr))
+
+	v.EachComplex128(func(index int, val complex128) bool {
+		collected[index] = collector(index, val)
+		return true
+	})
+
+	return &Value{data: collected}
+}

+ 2867 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/type_specific_codegen_test.go

@@ -0,0 +1,2867 @@
+package objx
+
+import (
+	"fmt"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+)
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInter(t *testing.T) {
+
+	val := interface{}("something")
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Inter())
+	assert.Equal(t, val, New(m).Get("value").MustInter())
+	assert.Equal(t, interface{}(nil), New(m).Get("nothing").Inter())
+	assert.Equal(t, val, New(m).Get("nothing").Inter("something"))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInter()
+	})
+
+}
+
+func TestInterSlice(t *testing.T) {
+
+	val := interface{}("something")
+	m := map[string]interface{}{"value": []interface{}{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").InterSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInterSlice()[0])
+	assert.Equal(t, []interface{}(nil), New(m).Get("nothing").InterSlice())
+	assert.Equal(t, val, New(m).Get("nothing").InterSlice([]interface{}{interface{}("something")})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInterSlice()
+	})
+
+}
+
+func TestIsInter(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: interface{}("something")}
+	assert.True(t, v.IsInter())
+
+	v = &Value{data: []interface{}{interface{}("something")}}
+	assert.True(t, v.IsInterSlice())
+
+}
+
+func TestEachInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+	count := 0
+	replacedVals := make([]interface{}, 0)
+	assert.Equal(t, v, v.EachInter(func(i int, val interface{}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInterSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInterSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInterSlice()[2])
+
+}
+
+func TestWhereInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	selected := v.WhereInter(func(i int, val interface{}) bool {
+		return i%2 == 0
+	}).MustInterSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	grouped := v.GroupInter(func(i int, val interface{}) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]interface{})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	rawArr := v.MustInterSlice()
+
+	replaced := v.ReplaceInter(func(index int, val interface{}) interface{} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInterSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInter(t *testing.T) {
+
+	v := &Value{data: []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}}
+
+	collected := v.CollectInter(func(index int, val interface{}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestMSI(t *testing.T) {
+
+	val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").MSI())
+	assert.Equal(t, val, New(m).Get("value").MustMSI())
+	assert.Equal(t, map[string]interface{}(nil), New(m).Get("nothing").MSI())
+	assert.Equal(t, val, New(m).Get("nothing").MSI(map[string]interface{}{"name": "Tyler"}))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustMSI()
+	})
+
+}
+
+func TestMSISlice(t *testing.T) {
+
+	val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
+	m := map[string]interface{}{"value": []map[string]interface{}{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").MSISlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustMSISlice()[0])
+	assert.Equal(t, []map[string]interface{}(nil), New(m).Get("nothing").MSISlice())
+	assert.Equal(t, val, New(m).Get("nothing").MSISlice([]map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustMSISlice()
+	})
+
+}
+
+func TestIsMSI(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: map[string]interface{}(map[string]interface{}{"name": "Tyler"})}
+	assert.True(t, v.IsMSI())
+
+	v = &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+	assert.True(t, v.IsMSISlice())
+
+}
+
+func TestEachMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+	count := 0
+	replacedVals := make([]map[string]interface{}, 0)
+	assert.Equal(t, v, v.EachMSI(func(i int, val map[string]interface{}) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustMSISlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustMSISlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustMSISlice()[2])
+
+}
+
+func TestWhereMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	selected := v.WhereMSI(func(i int, val map[string]interface{}) bool {
+		return i%2 == 0
+	}).MustMSISlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	grouped := v.GroupMSI(func(i int, val map[string]interface{}) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]map[string]interface{})
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	rawArr := v.MustMSISlice()
+
+	replaced := v.ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustMSISlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectMSI(t *testing.T) {
+
+	v := &Value{data: []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
+
+	collected := v.CollectMSI(func(index int, val map[string]interface{}) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestObjxMap(t *testing.T) {
+
+	val := (Map)(New(1))
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").ObjxMap())
+	assert.Equal(t, val, New(m).Get("value").MustObjxMap())
+	assert.Equal(t, (Map)(New(nil)), New(m).Get("nothing").ObjxMap())
+	assert.Equal(t, val, New(m).Get("nothing").ObjxMap(New(1)))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustObjxMap()
+	})
+
+}
+
+func TestObjxMapSlice(t *testing.T) {
+
+	val := (Map)(New(1))
+	m := map[string]interface{}{"value": [](Map){val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").ObjxMapSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustObjxMapSlice()[0])
+	assert.Equal(t, [](Map)(nil), New(m).Get("nothing").ObjxMapSlice())
+	assert.Equal(t, val, New(m).Get("nothing").ObjxMapSlice([](Map){(Map)(New(1))})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustObjxMapSlice()
+	})
+
+}
+
+func TestIsObjxMap(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: (Map)(New(1))}
+	assert.True(t, v.IsObjxMap())
+
+	v = &Value{data: [](Map){(Map)(New(1))}}
+	assert.True(t, v.IsObjxMapSlice())
+
+}
+
+func TestEachObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+	count := 0
+	replacedVals := make([](Map), 0)
+	assert.Equal(t, v, v.EachObjxMap(func(i int, val Map) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustObjxMapSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustObjxMapSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustObjxMapSlice()[2])
+
+}
+
+func TestWhereObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	selected := v.WhereObjxMap(func(i int, val Map) bool {
+		return i%2 == 0
+	}).MustObjxMapSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	grouped := v.GroupObjxMap(func(i int, val Map) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][](Map))
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	rawArr := v.MustObjxMapSlice()
+
+	replaced := v.ReplaceObjxMap(func(index int, val Map) Map {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustObjxMapSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectObjxMap(t *testing.T) {
+
+	v := &Value{data: [](Map){(Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1)), (Map)(New(1))}}
+
+	collected := v.CollectObjxMap(func(index int, val Map) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestBool(t *testing.T) {
+
+	val := bool(true)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Bool())
+	assert.Equal(t, val, New(m).Get("value").MustBool())
+	assert.Equal(t, bool(false), New(m).Get("nothing").Bool())
+	assert.Equal(t, val, New(m).Get("nothing").Bool(true))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustBool()
+	})
+
+}
+
+func TestBoolSlice(t *testing.T) {
+
+	val := bool(true)
+	m := map[string]interface{}{"value": []bool{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").BoolSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustBoolSlice()[0])
+	assert.Equal(t, []bool(nil), New(m).Get("nothing").BoolSlice())
+	assert.Equal(t, val, New(m).Get("nothing").BoolSlice([]bool{bool(true)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustBoolSlice()
+	})
+
+}
+
+func TestIsBool(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: bool(true)}
+	assert.True(t, v.IsBool())
+
+	v = &Value{data: []bool{bool(true)}}
+	assert.True(t, v.IsBoolSlice())
+
+}
+
+func TestEachBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true)}}
+	count := 0
+	replacedVals := make([]bool, 0)
+	assert.Equal(t, v, v.EachBool(func(i int, val bool) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustBoolSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustBoolSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustBoolSlice()[2])
+
+}
+
+func TestWhereBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	selected := v.WhereBool(func(i int, val bool) bool {
+		return i%2 == 0
+	}).MustBoolSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	grouped := v.GroupBool(func(i int, val bool) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]bool)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	rawArr := v.MustBoolSlice()
+
+	replaced := v.ReplaceBool(func(index int, val bool) bool {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustBoolSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectBool(t *testing.T) {
+
+	v := &Value{data: []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}}
+
+	collected := v.CollectBool(func(index int, val bool) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestStr(t *testing.T) {
+
+	val := string("hello")
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Str())
+	assert.Equal(t, val, New(m).Get("value").MustStr())
+	assert.Equal(t, string(""), New(m).Get("nothing").Str())
+	assert.Equal(t, val, New(m).Get("nothing").Str("hello"))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustStr()
+	})
+
+}
+
+func TestStrSlice(t *testing.T) {
+
+	val := string("hello")
+	m := map[string]interface{}{"value": []string{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").StrSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustStrSlice()[0])
+	assert.Equal(t, []string(nil), New(m).Get("nothing").StrSlice())
+	assert.Equal(t, val, New(m).Get("nothing").StrSlice([]string{string("hello")})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustStrSlice()
+	})
+
+}
+
+func TestIsStr(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: string("hello")}
+	assert.True(t, v.IsStr())
+
+	v = &Value{data: []string{string("hello")}}
+	assert.True(t, v.IsStrSlice())
+
+}
+
+func TestEachStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+	count := 0
+	replacedVals := make([]string, 0)
+	assert.Equal(t, v, v.EachStr(func(i int, val string) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustStrSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustStrSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustStrSlice()[2])
+
+}
+
+func TestWhereStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	selected := v.WhereStr(func(i int, val string) bool {
+		return i%2 == 0
+	}).MustStrSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	grouped := v.GroupStr(func(i int, val string) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]string)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	rawArr := v.MustStrSlice()
+
+	replaced := v.ReplaceStr(func(index int, val string) string {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustStrSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectStr(t *testing.T) {
+
+	v := &Value{data: []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}}
+
+	collected := v.CollectStr(func(index int, val string) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt(t *testing.T) {
+
+	val := int(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int())
+	assert.Equal(t, val, New(m).Get("value").MustInt())
+	assert.Equal(t, int(0), New(m).Get("nothing").Int())
+	assert.Equal(t, val, New(m).Get("nothing").Int(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt()
+	})
+
+}
+
+func TestIntSlice(t *testing.T) {
+
+	val := int(1)
+	m := map[string]interface{}{"value": []int{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").IntSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustIntSlice()[0])
+	assert.Equal(t, []int(nil), New(m).Get("nothing").IntSlice())
+	assert.Equal(t, val, New(m).Get("nothing").IntSlice([]int{int(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustIntSlice()
+	})
+
+}
+
+func TestIsInt(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int(1)}
+	assert.True(t, v.IsInt())
+
+	v = &Value{data: []int{int(1)}}
+	assert.True(t, v.IsIntSlice())
+
+}
+
+func TestEachInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1)}}
+	count := 0
+	replacedVals := make([]int, 0)
+	assert.Equal(t, v, v.EachInt(func(i int, val int) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustIntSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustIntSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustIntSlice()[2])
+
+}
+
+func TestWhereInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	selected := v.WhereInt(func(i int, val int) bool {
+		return i%2 == 0
+	}).MustIntSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	grouped := v.GroupInt(func(i int, val int) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	rawArr := v.MustIntSlice()
+
+	replaced := v.ReplaceInt(func(index int, val int) int {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustIntSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt(t *testing.T) {
+
+	v := &Value{data: []int{int(1), int(1), int(1), int(1), int(1), int(1)}}
+
+	collected := v.CollectInt(func(index int, val int) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt8(t *testing.T) {
+
+	val := int8(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int8())
+	assert.Equal(t, val, New(m).Get("value").MustInt8())
+	assert.Equal(t, int8(0), New(m).Get("nothing").Int8())
+	assert.Equal(t, val, New(m).Get("nothing").Int8(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt8()
+	})
+
+}
+
+func TestInt8Slice(t *testing.T) {
+
+	val := int8(1)
+	m := map[string]interface{}{"value": []int8{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int8Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt8Slice()[0])
+	assert.Equal(t, []int8(nil), New(m).Get("nothing").Int8Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int8Slice([]int8{int8(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt8Slice()
+	})
+
+}
+
+func TestIsInt8(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int8(1)}
+	assert.True(t, v.IsInt8())
+
+	v = &Value{data: []int8{int8(1)}}
+	assert.True(t, v.IsInt8Slice())
+
+}
+
+func TestEachInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1)}}
+	count := 0
+	replacedVals := make([]int8, 0)
+	assert.Equal(t, v, v.EachInt8(func(i int, val int8) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt8Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt8Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt8Slice()[2])
+
+}
+
+func TestWhereInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	selected := v.WhereInt8(func(i int, val int8) bool {
+		return i%2 == 0
+	}).MustInt8Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	grouped := v.GroupInt8(func(i int, val int8) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int8)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	rawArr := v.MustInt8Slice()
+
+	replaced := v.ReplaceInt8(func(index int, val int8) int8 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt8Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt8(t *testing.T) {
+
+	v := &Value{data: []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}}
+
+	collected := v.CollectInt8(func(index int, val int8) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt16(t *testing.T) {
+
+	val := int16(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int16())
+	assert.Equal(t, val, New(m).Get("value").MustInt16())
+	assert.Equal(t, int16(0), New(m).Get("nothing").Int16())
+	assert.Equal(t, val, New(m).Get("nothing").Int16(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt16()
+	})
+
+}
+
+func TestInt16Slice(t *testing.T) {
+
+	val := int16(1)
+	m := map[string]interface{}{"value": []int16{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int16Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt16Slice()[0])
+	assert.Equal(t, []int16(nil), New(m).Get("nothing").Int16Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int16Slice([]int16{int16(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt16Slice()
+	})
+
+}
+
+func TestIsInt16(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int16(1)}
+	assert.True(t, v.IsInt16())
+
+	v = &Value{data: []int16{int16(1)}}
+	assert.True(t, v.IsInt16Slice())
+
+}
+
+func TestEachInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1)}}
+	count := 0
+	replacedVals := make([]int16, 0)
+	assert.Equal(t, v, v.EachInt16(func(i int, val int16) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt16Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt16Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt16Slice()[2])
+
+}
+
+func TestWhereInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	selected := v.WhereInt16(func(i int, val int16) bool {
+		return i%2 == 0
+	}).MustInt16Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	grouped := v.GroupInt16(func(i int, val int16) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int16)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	rawArr := v.MustInt16Slice()
+
+	replaced := v.ReplaceInt16(func(index int, val int16) int16 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt16Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt16(t *testing.T) {
+
+	v := &Value{data: []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}}
+
+	collected := v.CollectInt16(func(index int, val int16) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt32(t *testing.T) {
+
+	val := int32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int32())
+	assert.Equal(t, val, New(m).Get("value").MustInt32())
+	assert.Equal(t, int32(0), New(m).Get("nothing").Int32())
+	assert.Equal(t, val, New(m).Get("nothing").Int32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt32()
+	})
+
+}
+
+func TestInt32Slice(t *testing.T) {
+
+	val := int32(1)
+	m := map[string]interface{}{"value": []int32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt32Slice()[0])
+	assert.Equal(t, []int32(nil), New(m).Get("nothing").Int32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int32Slice([]int32{int32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt32Slice()
+	})
+
+}
+
+func TestIsInt32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int32(1)}
+	assert.True(t, v.IsInt32())
+
+	v = &Value{data: []int32{int32(1)}}
+	assert.True(t, v.IsInt32Slice())
+
+}
+
+func TestEachInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1)}}
+	count := 0
+	replacedVals := make([]int32, 0)
+	assert.Equal(t, v, v.EachInt32(func(i int, val int32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt32Slice()[2])
+
+}
+
+func TestWhereInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	selected := v.WhereInt32(func(i int, val int32) bool {
+		return i%2 == 0
+	}).MustInt32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	grouped := v.GroupInt32(func(i int, val int32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	rawArr := v.MustInt32Slice()
+
+	replaced := v.ReplaceInt32(func(index int, val int32) int32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt32(t *testing.T) {
+
+	v := &Value{data: []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}}
+
+	collected := v.CollectInt32(func(index int, val int32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestInt64(t *testing.T) {
+
+	val := int64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int64())
+	assert.Equal(t, val, New(m).Get("value").MustInt64())
+	assert.Equal(t, int64(0), New(m).Get("nothing").Int64())
+	assert.Equal(t, val, New(m).Get("nothing").Int64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustInt64()
+	})
+
+}
+
+func TestInt64Slice(t *testing.T) {
+
+	val := int64(1)
+	m := map[string]interface{}{"value": []int64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Int64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustInt64Slice()[0])
+	assert.Equal(t, []int64(nil), New(m).Get("nothing").Int64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Int64Slice([]int64{int64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustInt64Slice()
+	})
+
+}
+
+func TestIsInt64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: int64(1)}
+	assert.True(t, v.IsInt64())
+
+	v = &Value{data: []int64{int64(1)}}
+	assert.True(t, v.IsInt64Slice())
+
+}
+
+func TestEachInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1)}}
+	count := 0
+	replacedVals := make([]int64, 0)
+	assert.Equal(t, v, v.EachInt64(func(i int, val int64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustInt64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustInt64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustInt64Slice()[2])
+
+}
+
+func TestWhereInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	selected := v.WhereInt64(func(i int, val int64) bool {
+		return i%2 == 0
+	}).MustInt64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	grouped := v.GroupInt64(func(i int, val int64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]int64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	rawArr := v.MustInt64Slice()
+
+	replaced := v.ReplaceInt64(func(index int, val int64) int64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustInt64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectInt64(t *testing.T) {
+
+	v := &Value{data: []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}}
+
+	collected := v.CollectInt64(func(index int, val int64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint(t *testing.T) {
+
+	val := uint(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint())
+	assert.Equal(t, val, New(m).Get("value").MustUint())
+	assert.Equal(t, uint(0), New(m).Get("nothing").Uint())
+	assert.Equal(t, val, New(m).Get("nothing").Uint(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint()
+	})
+
+}
+
+func TestUintSlice(t *testing.T) {
+
+	val := uint(1)
+	m := map[string]interface{}{"value": []uint{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").UintSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUintSlice()[0])
+	assert.Equal(t, []uint(nil), New(m).Get("nothing").UintSlice())
+	assert.Equal(t, val, New(m).Get("nothing").UintSlice([]uint{uint(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUintSlice()
+	})
+
+}
+
+func TestIsUint(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint(1)}
+	assert.True(t, v.IsUint())
+
+	v = &Value{data: []uint{uint(1)}}
+	assert.True(t, v.IsUintSlice())
+
+}
+
+func TestEachUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1)}}
+	count := 0
+	replacedVals := make([]uint, 0)
+	assert.Equal(t, v, v.EachUint(func(i int, val uint) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUintSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUintSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUintSlice()[2])
+
+}
+
+func TestWhereUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	selected := v.WhereUint(func(i int, val uint) bool {
+		return i%2 == 0
+	}).MustUintSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	grouped := v.GroupUint(func(i int, val uint) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	rawArr := v.MustUintSlice()
+
+	replaced := v.ReplaceUint(func(index int, val uint) uint {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUintSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint(t *testing.T) {
+
+	v := &Value{data: []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}}
+
+	collected := v.CollectUint(func(index int, val uint) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint8(t *testing.T) {
+
+	val := uint8(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint8())
+	assert.Equal(t, val, New(m).Get("value").MustUint8())
+	assert.Equal(t, uint8(0), New(m).Get("nothing").Uint8())
+	assert.Equal(t, val, New(m).Get("nothing").Uint8(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint8()
+	})
+
+}
+
+func TestUint8Slice(t *testing.T) {
+
+	val := uint8(1)
+	m := map[string]interface{}{"value": []uint8{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint8Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint8Slice()[0])
+	assert.Equal(t, []uint8(nil), New(m).Get("nothing").Uint8Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint8Slice([]uint8{uint8(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint8Slice()
+	})
+
+}
+
+func TestIsUint8(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint8(1)}
+	assert.True(t, v.IsUint8())
+
+	v = &Value{data: []uint8{uint8(1)}}
+	assert.True(t, v.IsUint8Slice())
+
+}
+
+func TestEachUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+	count := 0
+	replacedVals := make([]uint8, 0)
+	assert.Equal(t, v, v.EachUint8(func(i int, val uint8) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint8Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint8Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint8Slice()[2])
+
+}
+
+func TestWhereUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	selected := v.WhereUint8(func(i int, val uint8) bool {
+		return i%2 == 0
+	}).MustUint8Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	grouped := v.GroupUint8(func(i int, val uint8) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint8)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	rawArr := v.MustUint8Slice()
+
+	replaced := v.ReplaceUint8(func(index int, val uint8) uint8 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint8Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint8(t *testing.T) {
+
+	v := &Value{data: []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}}
+
+	collected := v.CollectUint8(func(index int, val uint8) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint16(t *testing.T) {
+
+	val := uint16(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint16())
+	assert.Equal(t, val, New(m).Get("value").MustUint16())
+	assert.Equal(t, uint16(0), New(m).Get("nothing").Uint16())
+	assert.Equal(t, val, New(m).Get("nothing").Uint16(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint16()
+	})
+
+}
+
+func TestUint16Slice(t *testing.T) {
+
+	val := uint16(1)
+	m := map[string]interface{}{"value": []uint16{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint16Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint16Slice()[0])
+	assert.Equal(t, []uint16(nil), New(m).Get("nothing").Uint16Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint16Slice([]uint16{uint16(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint16Slice()
+	})
+
+}
+
+func TestIsUint16(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint16(1)}
+	assert.True(t, v.IsUint16())
+
+	v = &Value{data: []uint16{uint16(1)}}
+	assert.True(t, v.IsUint16Slice())
+
+}
+
+func TestEachUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+	count := 0
+	replacedVals := make([]uint16, 0)
+	assert.Equal(t, v, v.EachUint16(func(i int, val uint16) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint16Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint16Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint16Slice()[2])
+
+}
+
+func TestWhereUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	selected := v.WhereUint16(func(i int, val uint16) bool {
+		return i%2 == 0
+	}).MustUint16Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	grouped := v.GroupUint16(func(i int, val uint16) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint16)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	rawArr := v.MustUint16Slice()
+
+	replaced := v.ReplaceUint16(func(index int, val uint16) uint16 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint16Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint16(t *testing.T) {
+
+	v := &Value{data: []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}}
+
+	collected := v.CollectUint16(func(index int, val uint16) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint32(t *testing.T) {
+
+	val := uint32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint32())
+	assert.Equal(t, val, New(m).Get("value").MustUint32())
+	assert.Equal(t, uint32(0), New(m).Get("nothing").Uint32())
+	assert.Equal(t, val, New(m).Get("nothing").Uint32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint32()
+	})
+
+}
+
+func TestUint32Slice(t *testing.T) {
+
+	val := uint32(1)
+	m := map[string]interface{}{"value": []uint32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint32Slice()[0])
+	assert.Equal(t, []uint32(nil), New(m).Get("nothing").Uint32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint32Slice([]uint32{uint32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint32Slice()
+	})
+
+}
+
+func TestIsUint32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint32(1)}
+	assert.True(t, v.IsUint32())
+
+	v = &Value{data: []uint32{uint32(1)}}
+	assert.True(t, v.IsUint32Slice())
+
+}
+
+func TestEachUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+	count := 0
+	replacedVals := make([]uint32, 0)
+	assert.Equal(t, v, v.EachUint32(func(i int, val uint32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint32Slice()[2])
+
+}
+
+func TestWhereUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	selected := v.WhereUint32(func(i int, val uint32) bool {
+		return i%2 == 0
+	}).MustUint32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	grouped := v.GroupUint32(func(i int, val uint32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	rawArr := v.MustUint32Slice()
+
+	replaced := v.ReplaceUint32(func(index int, val uint32) uint32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint32(t *testing.T) {
+
+	v := &Value{data: []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}}
+
+	collected := v.CollectUint32(func(index int, val uint32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUint64(t *testing.T) {
+
+	val := uint64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint64())
+	assert.Equal(t, val, New(m).Get("value").MustUint64())
+	assert.Equal(t, uint64(0), New(m).Get("nothing").Uint64())
+	assert.Equal(t, val, New(m).Get("nothing").Uint64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUint64()
+	})
+
+}
+
+func TestUint64Slice(t *testing.T) {
+
+	val := uint64(1)
+	m := map[string]interface{}{"value": []uint64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uint64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUint64Slice()[0])
+	assert.Equal(t, []uint64(nil), New(m).Get("nothing").Uint64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Uint64Slice([]uint64{uint64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUint64Slice()
+	})
+
+}
+
+func TestIsUint64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uint64(1)}
+	assert.True(t, v.IsUint64())
+
+	v = &Value{data: []uint64{uint64(1)}}
+	assert.True(t, v.IsUint64Slice())
+
+}
+
+func TestEachUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+	count := 0
+	replacedVals := make([]uint64, 0)
+	assert.Equal(t, v, v.EachUint64(func(i int, val uint64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUint64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUint64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUint64Slice()[2])
+
+}
+
+func TestWhereUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	selected := v.WhereUint64(func(i int, val uint64) bool {
+		return i%2 == 0
+	}).MustUint64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	grouped := v.GroupUint64(func(i int, val uint64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uint64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	rawArr := v.MustUint64Slice()
+
+	replaced := v.ReplaceUint64(func(index int, val uint64) uint64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUint64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUint64(t *testing.T) {
+
+	v := &Value{data: []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}}
+
+	collected := v.CollectUint64(func(index int, val uint64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestUintptr(t *testing.T) {
+
+	val := uintptr(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Uintptr())
+	assert.Equal(t, val, New(m).Get("value").MustUintptr())
+	assert.Equal(t, uintptr(0), New(m).Get("nothing").Uintptr())
+	assert.Equal(t, val, New(m).Get("nothing").Uintptr(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustUintptr()
+	})
+
+}
+
+func TestUintptrSlice(t *testing.T) {
+
+	val := uintptr(1)
+	m := map[string]interface{}{"value": []uintptr{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").UintptrSlice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustUintptrSlice()[0])
+	assert.Equal(t, []uintptr(nil), New(m).Get("nothing").UintptrSlice())
+	assert.Equal(t, val, New(m).Get("nothing").UintptrSlice([]uintptr{uintptr(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustUintptrSlice()
+	})
+
+}
+
+func TestIsUintptr(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: uintptr(1)}
+	assert.True(t, v.IsUintptr())
+
+	v = &Value{data: []uintptr{uintptr(1)}}
+	assert.True(t, v.IsUintptrSlice())
+
+}
+
+func TestEachUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+	count := 0
+	replacedVals := make([]uintptr, 0)
+	assert.Equal(t, v, v.EachUintptr(func(i int, val uintptr) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustUintptrSlice()[0])
+	assert.Equal(t, replacedVals[1], v.MustUintptrSlice()[1])
+	assert.Equal(t, replacedVals[2], v.MustUintptrSlice()[2])
+
+}
+
+func TestWhereUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	selected := v.WhereUintptr(func(i int, val uintptr) bool {
+		return i%2 == 0
+	}).MustUintptrSlice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	grouped := v.GroupUintptr(func(i int, val uintptr) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]uintptr)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	rawArr := v.MustUintptrSlice()
+
+	replaced := v.ReplaceUintptr(func(index int, val uintptr) uintptr {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustUintptrSlice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectUintptr(t *testing.T) {
+
+	v := &Value{data: []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}}
+
+	collected := v.CollectUintptr(func(index int, val uintptr) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestFloat32(t *testing.T) {
+
+	val := float32(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float32())
+	assert.Equal(t, val, New(m).Get("value").MustFloat32())
+	assert.Equal(t, float32(0), New(m).Get("nothing").Float32())
+	assert.Equal(t, val, New(m).Get("nothing").Float32(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustFloat32()
+	})
+
+}
+
+func TestFloat32Slice(t *testing.T) {
+
+	val := float32(1)
+	m := map[string]interface{}{"value": []float32{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float32Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustFloat32Slice()[0])
+	assert.Equal(t, []float32(nil), New(m).Get("nothing").Float32Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Float32Slice([]float32{float32(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustFloat32Slice()
+	})
+
+}
+
+func TestIsFloat32(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: float32(1)}
+	assert.True(t, v.IsFloat32())
+
+	v = &Value{data: []float32{float32(1)}}
+	assert.True(t, v.IsFloat32Slice())
+
+}
+
+func TestEachFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1)}}
+	count := 0
+	replacedVals := make([]float32, 0)
+	assert.Equal(t, v, v.EachFloat32(func(i int, val float32) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustFloat32Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustFloat32Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustFloat32Slice()[2])
+
+}
+
+func TestWhereFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	selected := v.WhereFloat32(func(i int, val float32) bool {
+		return i%2 == 0
+	}).MustFloat32Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	grouped := v.GroupFloat32(func(i int, val float32) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]float32)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	rawArr := v.MustFloat32Slice()
+
+	replaced := v.ReplaceFloat32(func(index int, val float32) float32 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustFloat32Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectFloat32(t *testing.T) {
+
+	v := &Value{data: []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}}
+
+	collected := v.CollectFloat32(func(index int, val float32) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestFloat64(t *testing.T) {
+
+	val := float64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float64())
+	assert.Equal(t, val, New(m).Get("value").MustFloat64())
+	assert.Equal(t, float64(0), New(m).Get("nothing").Float64())
+	assert.Equal(t, val, New(m).Get("nothing").Float64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustFloat64()
+	})
+
+}
+
+func TestFloat64Slice(t *testing.T) {
+
+	val := float64(1)
+	m := map[string]interface{}{"value": []float64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Float64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustFloat64Slice()[0])
+	assert.Equal(t, []float64(nil), New(m).Get("nothing").Float64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Float64Slice([]float64{float64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustFloat64Slice()
+	})
+
+}
+
+func TestIsFloat64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: float64(1)}
+	assert.True(t, v.IsFloat64())
+
+	v = &Value{data: []float64{float64(1)}}
+	assert.True(t, v.IsFloat64Slice())
+
+}
+
+func TestEachFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1)}}
+	count := 0
+	replacedVals := make([]float64, 0)
+	assert.Equal(t, v, v.EachFloat64(func(i int, val float64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustFloat64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustFloat64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustFloat64Slice()[2])
+
+}
+
+func TestWhereFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	selected := v.WhereFloat64(func(i int, val float64) bool {
+		return i%2 == 0
+	}).MustFloat64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	grouped := v.GroupFloat64(func(i int, val float64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]float64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	rawArr := v.MustFloat64Slice()
+
+	replaced := v.ReplaceFloat64(func(index int, val float64) float64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustFloat64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectFloat64(t *testing.T) {
+
+	v := &Value{data: []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}}
+
+	collected := v.CollectFloat64(func(index int, val float64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestComplex64(t *testing.T) {
+
+	val := complex64(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex64())
+	assert.Equal(t, val, New(m).Get("value").MustComplex64())
+	assert.Equal(t, complex64(0), New(m).Get("nothing").Complex64())
+	assert.Equal(t, val, New(m).Get("nothing").Complex64(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustComplex64()
+	})
+
+}
+
+func TestComplex64Slice(t *testing.T) {
+
+	val := complex64(1)
+	m := map[string]interface{}{"value": []complex64{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex64Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustComplex64Slice()[0])
+	assert.Equal(t, []complex64(nil), New(m).Get("nothing").Complex64Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Complex64Slice([]complex64{complex64(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustComplex64Slice()
+	})
+
+}
+
+func TestIsComplex64(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: complex64(1)}
+	assert.True(t, v.IsComplex64())
+
+	v = &Value{data: []complex64{complex64(1)}}
+	assert.True(t, v.IsComplex64Slice())
+
+}
+
+func TestEachComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+	count := 0
+	replacedVals := make([]complex64, 0)
+	assert.Equal(t, v, v.EachComplex64(func(i int, val complex64) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustComplex64Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustComplex64Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustComplex64Slice()[2])
+
+}
+
+func TestWhereComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	selected := v.WhereComplex64(func(i int, val complex64) bool {
+		return i%2 == 0
+	}).MustComplex64Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	grouped := v.GroupComplex64(func(i int, val complex64) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]complex64)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	rawArr := v.MustComplex64Slice()
+
+	replaced := v.ReplaceComplex64(func(index int, val complex64) complex64 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustComplex64Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectComplex64(t *testing.T) {
+
+	v := &Value{data: []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}}
+
+	collected := v.CollectComplex64(func(index int, val complex64) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func TestComplex128(t *testing.T) {
+
+	val := complex128(1)
+	m := map[string]interface{}{"value": val, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex128())
+	assert.Equal(t, val, New(m).Get("value").MustComplex128())
+	assert.Equal(t, complex128(0), New(m).Get("nothing").Complex128())
+	assert.Equal(t, val, New(m).Get("nothing").Complex128(1))
+
+	assert.Panics(t, func() {
+		New(m).Get("age").MustComplex128()
+	})
+
+}
+
+func TestComplex128Slice(t *testing.T) {
+
+	val := complex128(1)
+	m := map[string]interface{}{"value": []complex128{val}, "nothing": nil}
+	assert.Equal(t, val, New(m).Get("value").Complex128Slice()[0])
+	assert.Equal(t, val, New(m).Get("value").MustComplex128Slice()[0])
+	assert.Equal(t, []complex128(nil), New(m).Get("nothing").Complex128Slice())
+	assert.Equal(t, val, New(m).Get("nothing").Complex128Slice([]complex128{complex128(1)})[0])
+
+	assert.Panics(t, func() {
+		New(m).Get("nothing").MustComplex128Slice()
+	})
+
+}
+
+func TestIsComplex128(t *testing.T) {
+
+	var v *Value
+
+	v = &Value{data: complex128(1)}
+	assert.True(t, v.IsComplex128())
+
+	v = &Value{data: []complex128{complex128(1)}}
+	assert.True(t, v.IsComplex128Slice())
+
+}
+
+func TestEachComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+	count := 0
+	replacedVals := make([]complex128, 0)
+	assert.Equal(t, v, v.EachComplex128(func(i int, val complex128) bool {
+
+		count++
+		replacedVals = append(replacedVals, val)
+
+		// abort early
+		if i == 2 {
+			return false
+		}
+
+		return true
+
+	}))
+
+	assert.Equal(t, count, 3)
+	assert.Equal(t, replacedVals[0], v.MustComplex128Slice()[0])
+	assert.Equal(t, replacedVals[1], v.MustComplex128Slice()[1])
+	assert.Equal(t, replacedVals[2], v.MustComplex128Slice()[2])
+
+}
+
+func TestWhereComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	selected := v.WhereComplex128(func(i int, val complex128) bool {
+		return i%2 == 0
+	}).MustComplex128Slice()
+
+	assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroupComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	grouped := v.GroupComplex128(func(i int, val complex128) string {
+		return fmt.Sprintf("%v", i%2 == 0)
+	}).data.(map[string][]complex128)
+
+	assert.Equal(t, 2, len(grouped))
+	assert.Equal(t, 3, len(grouped["true"]))
+	assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplaceComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	rawArr := v.MustComplex128Slice()
+
+	replaced := v.ReplaceComplex128(func(index int, val complex128) complex128 {
+		if index < len(rawArr)-1 {
+			return rawArr[index+1]
+		}
+		return rawArr[0]
+	})
+
+	replacedArr := replaced.MustComplex128Slice()
+	if assert.Equal(t, 6, len(replacedArr)) {
+		assert.Equal(t, replacedArr[0], rawArr[1])
+		assert.Equal(t, replacedArr[1], rawArr[2])
+		assert.Equal(t, replacedArr[2], rawArr[3])
+		assert.Equal(t, replacedArr[3], rawArr[4])
+		assert.Equal(t, replacedArr[4], rawArr[5])
+		assert.Equal(t, replacedArr[5], rawArr[0])
+	}
+
+}
+
+func TestCollectComplex128(t *testing.T) {
+
+	v := &Value{data: []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}}
+
+	collected := v.CollectComplex128(func(index int, val complex128) interface{} {
+		return index
+	})
+
+	collectedArr := collected.MustInterSlice()
+	if assert.Equal(t, 6, len(collectedArr)) {
+		assert.Equal(t, collectedArr[0], 0)
+		assert.Equal(t, collectedArr[1], 1)
+		assert.Equal(t, collectedArr[2], 2)
+		assert.Equal(t, collectedArr[3], 3)
+		assert.Equal(t, collectedArr[4], 4)
+		assert.Equal(t, collectedArr[5], 5)
+	}
+
+}

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value.go

@@ -0,0 +1,13 @@
+package objx
+
+// Value provides methods for extracting interface{} data in various
+// types.
+type Value struct {
+	// data contains the raw data being managed by this Value
+	data interface{}
+}
+
+// Data returns the raw data contained by this Value
+func (v *Value) Data() interface{} {
+	return v.data
+}

+ 1 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/value_test.go

@@ -0,0 +1 @@
+package objx

+ 853 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go

@@ -0,0 +1,853 @@
+package assert
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"math"
+	"reflect"
+	"regexp"
+	"runtime"
+	"strings"
+	"time"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+}
+
+// Comparison a custom function that returns true on success and false on failure
+type Comparison func() (success bool)
+
+/*
+	Helper functions
+*/
+
+// ObjectsAreEqual determines if two objects are considered equal.
+//
+// This function does no assertion of any kind.
+func ObjectsAreEqual(expected, actual interface{}) bool {
+
+	if expected == nil || actual == nil {
+		return expected == actual
+	}
+
+	if reflect.DeepEqual(expected, actual) {
+		return true
+	}
+
+	return false
+
+}
+
+// ObjectsAreEqualValues gets whether two objects are equal, or if their
+// values are equal.
+func ObjectsAreEqualValues(expected, actual interface{}) bool {
+	if ObjectsAreEqual(expected, actual) {
+		return true
+	}
+
+	actualType := reflect.TypeOf(actual)
+	expectedValue := reflect.ValueOf(expected)
+	if expectedValue.Type().ConvertibleTo(actualType) {
+		// Attempt comparison after type conversion
+		if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
+			return true
+		}
+	}
+
+	return false
+}
+
+/* CallerInfo is necessary because the assert functions use the testing object
+internally, causing it to print the file:line of the assert method, rather than where
+the problem actually occured in calling code.*/
+
+// CallerInfo returns a string containing the file and line number of the assert call
+// that failed.
+func CallerInfo() string {
+
+	file := ""
+	line := 0
+	ok := false
+
+	for i := 0; ; i++ {
+		_, file, line, ok = runtime.Caller(i)
+		if !ok {
+			return ""
+		}
+		parts := strings.Split(file, "/")
+		dir := parts[len(parts)-2]
+		file = parts[len(parts)-1]
+		if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
+			break
+		}
+	}
+
+	return fmt.Sprintf("%s:%d", file, line)
+}
+
+// getWhitespaceString returns a string that is long enough to overwrite the default
+// output from the go testing framework.
+func getWhitespaceString() string {
+
+	_, file, line, ok := runtime.Caller(1)
+	if !ok {
+		return ""
+	}
+	parts := strings.Split(file, "/")
+	file = parts[len(parts)-1]
+
+	return strings.Repeat(" ", len(fmt.Sprintf("%s:%d:      ", file, line)))
+
+}
+
+func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
+	if len(msgAndArgs) == 0 || msgAndArgs == nil {
+		return ""
+	}
+	if len(msgAndArgs) == 1 {
+		return msgAndArgs[0].(string)
+	}
+	if len(msgAndArgs) > 1 {
+		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+	}
+	return ""
+}
+
+// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's
+// test printing (see inner comment for specifics)
+func indentMessageLines(message string, tabs int) string {
+	outBuf := new(bytes.Buffer)
+
+	for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
+		if i != 0 {
+			outBuf.WriteRune('\n')
+		}
+		for ii := 0; ii < tabs; ii++ {
+			outBuf.WriteRune('\t')
+			// Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter
+			// by 1 prematurely.
+			if ii == 0 && i > 0 {
+				ii++
+			}
+		}
+		outBuf.WriteString(scanner.Text())
+	}
+
+	return outBuf.String()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+
+	if len(message) > 0 {
+		t.Errorf("\r%s\r\tLocation:\t%s\n"+
+			"\r\tError:%s\n"+
+			"\r\tMessages:\t%s\n\r",
+			getWhitespaceString(),
+			CallerInfo(),
+			indentMessageLines(failureMessage, 2),
+			message)
+	} else {
+		t.Errorf("\r%s\r\tLocation:\t%s\n"+
+			"\r\tError:%s\n\r",
+			getWhitespaceString(),
+			CallerInfo(),
+			indentMessageLines(failureMessage, 2))
+	}
+
+	return false
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+	interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+	if !reflect.TypeOf(object).Implements(interfaceType) {
+		return Fail(t, fmt.Sprintf("Object must implement %v", interfaceType), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
+		return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqual(expected, actual) {
+		return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+			"        != %#v (actual)", expected, actual), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if !ObjectsAreEqualValues(expected, actual) {
+		return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+			"        != %#v (actual)", expected, actual), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// Exactly asserts that two objects are equal is value and type.
+//
+//    assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	aType := reflect.TypeOf(expected)
+	bType := reflect.TypeOf(actual)
+
+	if aType != bType {
+		return Fail(t, "Types expected to match exactly", "%v != %v", aType, bType)
+	}
+
+	return Equal(t, expected, actual, msgAndArgs...)
+
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(t, err, "err should be something")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	success := true
+
+	if object == nil {
+		success = false
+	} else {
+		value := reflect.ValueOf(object)
+		kind := value.Kind()
+		if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
+			success = false
+		}
+	}
+
+	if !success {
+		Fail(t, "Expected not to be nil.", msgAndArgs...)
+	}
+
+	return success
+}
+
+// isNil checks if a specified object is nil or not, without Failing.
+func isNil(object interface{}) bool {
+	if object == nil {
+		return true
+	}
+
+	value := reflect.ValueOf(object)
+	kind := value.Kind()
+	if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
+		return true
+	}
+
+	return false
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(t, err, "err should be nothing")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	if isNil(object) {
+		return true
+	}
+	return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
+}
+
+var zeros = []interface{}{
+	int(0),
+	int8(0),
+	int16(0),
+	int32(0),
+	int64(0),
+	uint(0),
+	uint8(0),
+	uint16(0),
+	uint32(0),
+	uint64(0),
+	float32(0),
+	float64(0),
+}
+
+// isEmpty gets whether the specified object is considered empty or not.
+func isEmpty(object interface{}) bool {
+
+	if object == nil {
+		return true
+	} else if object == "" {
+		return true
+	} else if object == false {
+		return true
+	}
+
+	for _, v := range zeros {
+		if object == v {
+			return true
+		}
+	}
+
+	objValue := reflect.ValueOf(object)
+
+	switch objValue.Kind() {
+	case reflect.Map:
+		fallthrough
+	case reflect.Slice, reflect.Chan:
+		{
+			return (objValue.Len() == 0)
+		}
+	case reflect.Ptr:
+		{
+			switch object.(type) {
+			case *time.Time:
+				return object.(*time.Time).IsZero()
+			default:
+				return false
+			}
+		}
+	}
+	return false
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Empty(t, obj)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	pass := isEmpty(object)
+	if !pass {
+		Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmpty(t, obj) {
+//   assert.Equal(t, "two", obj[1])
+// }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+	pass := !isEmpty(object)
+	if !pass {
+		Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+
+}
+
+// getLen try to get length of object.
+// return (false, 0) if impossible.
+func getLen(x interface{}) (ok bool, length int) {
+	v := reflect.ValueOf(x)
+	defer func() {
+		if e := recover(); e != nil {
+			ok = false
+		}
+	}()
+	return true, v.Len()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(t, mySlice, 3, "The size of slice is not 3")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+	ok, l := getLen(object)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
+	}
+
+	if l != length {
+		return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
+	}
+	return true
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(t, myBool, "myBool should be true")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+	if value != true {
+		return Fail(t, "Should be true", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// False asserts that the specified value is true.
+//
+//    assert.False(t, myBool, "myBool should be false")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+	if value != false {
+		return Fail(t, "Should be false", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+	if ObjectsAreEqual(expected, actual) {
+		return Fail(t, "Should not be equal", msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// containsElement try loop over the list check if the list includes the element.
+// return (false, false) if impossible.
+// return (true, false) if element was not found.
+// return (true, true) if element was found.
+func includeElement(list interface{}, element interface{}) (ok, found bool) {
+
+	listValue := reflect.ValueOf(list)
+	elementValue := reflect.ValueOf(element)
+	defer func() {
+		if e := recover(); e != nil {
+			ok = false
+			found = false
+		}
+	}()
+
+	if reflect.TypeOf(list).Kind() == reflect.String {
+		return true, strings.Contains(listValue.String(), elementValue.String())
+	}
+
+	for i := 0; i < listValue.Len(); i++ {
+		if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
+			return true, true
+		}
+	}
+	return true, false
+
+}
+
+// Contains asserts that the specified string or list(array, slice...) contains the
+// specified substring or element.
+//
+//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
+//    assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+	ok, found := includeElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if !found {
+		return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// NotContains asserts that the specified string or list(array, slice...) does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+	ok, found := includeElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if found {
+		return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
+	}
+
+	return true
+
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+	result := comp()
+	if !result {
+		Fail(t, "Condition failed!", msgAndArgs...)
+	}
+	return result
+}
+
+// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
+// methods, and represents a simple func that takes no arguments, and returns nothing.
+type PanicTestFunc func()
+
+// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
+func didPanic(f PanicTestFunc) (bool, interface{}) {
+
+	didPanic := false
+	var message interface{}
+	func() {
+
+		defer func() {
+			if message = recover(); message != nil {
+				didPanic = true
+			}
+		}()
+
+		// call the target function
+		f()
+
+	}()
+
+	return didPanic, message
+
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(t, func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+	if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(t, func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+	if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+	}
+
+	return true
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+
+	dt := expected.Sub(actual)
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+func toFloat(x interface{}) (float64, bool) {
+	var xf float64
+	xok := true
+
+	switch xn := x.(type) {
+	case uint8:
+		xf = float64(xn)
+	case uint16:
+		xf = float64(xn)
+	case uint32:
+		xf = float64(xn)
+	case uint64:
+		xf = float64(xn)
+	case int:
+		xf = float64(xn)
+	case int8:
+		xf = float64(xn)
+	case int16:
+		xf = float64(xn)
+	case int32:
+		xf = float64(xn)
+	case int64:
+		xf = float64(xn)
+	case float32:
+		xf = float64(xn)
+	case float64:
+		xf = float64(xn)
+	default:
+		xok = false
+	}
+
+	return xf, xok
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+
+	if !aok || !bok {
+		return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
+	}
+
+	if math.IsNaN(af) {
+		return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...)
+	}
+
+	if math.IsNaN(bf) {
+		return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
+	}
+
+	dt := af - bf
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Slice ||
+		reflect.TypeOf(expected).Kind() != reflect.Slice {
+		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+	}
+
+	actualSlice := reflect.ValueOf(actual)
+	expectedSlice := reflect.ValueOf(expected)
+
+	for i := 0; i < actualSlice.Len(); i++ {
+		result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
+		if !result {
+			return result
+		}
+	}
+
+	return true
+}
+
+// min(|expected|, |actual|) * epsilon
+func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+
+	if !aok || !bok {
+		// invalid input
+		return 0
+	}
+
+	if af < 0 {
+		af = -af
+	}
+	if bf < 0 {
+		bf = -bf
+	}
+	var delta float64
+	if af < bf {
+		delta = af * epsilon
+	} else {
+		delta = bf * epsilon
+	}
+	return delta
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	delta := calcEpsilonDelta(expected, actual, epsilon)
+
+	return InDelta(t, expected, actual, delta, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
+func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Slice ||
+		reflect.TypeOf(expected).Kind() != reflect.Slice {
+		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+	}
+
+	actualSlice := reflect.ValueOf(actual)
+	expectedSlice := reflect.ValueOf(expected)
+
+	for i := 0; i < actualSlice.Len(); i++ {
+		result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
+		if !result {
+			return result
+		}
+	}
+
+	return true
+}
+
+/*
+	Errors
+*/
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+//	   assert.Equal(t, actualObj, expectedObj)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+	if isNil(err) {
+		return true
+	}
+
+	return Fail(t, fmt.Sprintf("No error is expected but got %v", err), msgAndArgs...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//	   assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+	return NotNil(t, err, "An error is expected but got nil. %s", message)
+
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//	   assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+	if !NotNil(t, theError, "An error is expected but got nil. %s", message) {
+		return false
+	}
+	s := "An error with value \"%s\" is expected but got \"%s\". %s"
+	return Equal(t, theError.Error(), errString,
+		s, errString, theError.Error(), message)
+}
+
+// matchRegexp return true if a specified regexp matches a string.
+func matchRegexp(rx interface{}, str interface{}) bool {
+
+	var r *regexp.Regexp
+	if rr, ok := rx.(*regexp.Regexp); ok {
+		r = rr
+	} else {
+		r = regexp.MustCompile(fmt.Sprint(rx))
+	}
+
+	return (r.FindStringIndex(fmt.Sprint(str)) != nil)
+
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+
+	match := matchRegexp(rx, str)
+
+	if !match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return match
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	match := matchRegexp(rx, str)
+
+	if match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return !match
+
+}

+ 791 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions_test.go

@@ -0,0 +1,791 @@
+package assert
+
+import (
+	"errors"
+	"math"
+	"regexp"
+	"testing"
+	"time"
+)
+
+// AssertionTesterInterface defines an interface to be used for testing assertion methods
+type AssertionTesterInterface interface {
+	TestMethod()
+}
+
+// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
+type AssertionTesterConformingObject struct {
+}
+
+func (a *AssertionTesterConformingObject) TestMethod() {
+}
+
+// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
+type AssertionTesterNonConformingObject struct {
+}
+
+func TestObjectsAreEqual(t *testing.T) {
+
+	if !ObjectsAreEqual("Hello World", "Hello World") {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(123, 123) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(123.5, 123.5) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual([]byte("Hello World"), []byte("Hello World")) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if !ObjectsAreEqual(nil, nil) {
+		t.Error("objectsAreEqual should return true")
+	}
+	if ObjectsAreEqual(map[int]int{5: 10}, map[int]int{10: 20}) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual('x', "x") {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual("x", 'x') {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(0, 0.1) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(0.1, 0) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if ObjectsAreEqual(uint32(10), int32(10)) {
+		t.Error("objectsAreEqual should return false")
+	}
+	if !ObjectsAreEqualValues(uint32(10), int32(10)) {
+		t.Error("ObjectsAreEqualValues should return true")
+	}
+
+}
+
+func TestImplements(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+		t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+	}
+	if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+		t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+	}
+
+}
+
+func TestIsType(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+	}
+	if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+		t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+	}
+
+}
+
+func TestEqual(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Equal(mockT, "Hello World", "Hello World") {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, 123, 123) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, 123.5, 123.5) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, []byte("Hello World"), []byte("Hello World")) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, nil, nil) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, int32(123), int32(123)) {
+		t.Error("Equal should return true")
+	}
+	if !Equal(mockT, uint64(123), uint64(123)) {
+		t.Error("Equal should return true")
+	}
+
+}
+
+func TestNotNil(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotNil(mockT, new(AssertionTesterConformingObject)) {
+		t.Error("NotNil should return true: object is not nil")
+	}
+	if NotNil(mockT, nil) {
+		t.Error("NotNil should return false: object is nil")
+	}
+
+}
+
+func TestNil(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Nil(mockT, nil) {
+		t.Error("Nil should return true: object is nil")
+	}
+	if Nil(mockT, new(AssertionTesterConformingObject)) {
+		t.Error("Nil should return false: object is not nil")
+	}
+
+}
+
+func TestTrue(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !True(mockT, true) {
+		t.Error("True should return true")
+	}
+	if True(mockT, false) {
+		t.Error("True should return false")
+	}
+
+}
+
+func TestFalse(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !False(mockT, false) {
+		t.Error("False should return true")
+	}
+	if False(mockT, true) {
+		t.Error("False should return false")
+	}
+
+}
+
+func TestExactly(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	a := float32(1)
+	b := float64(1)
+	c := float32(1)
+	d := float32(2)
+
+	if Exactly(mockT, a, b) {
+		t.Error("Exactly should return false")
+	}
+	if Exactly(mockT, a, d) {
+		t.Error("Exactly should return false")
+	}
+	if !Exactly(mockT, a, c) {
+		t.Error("Exactly should return true")
+	}
+
+	if Exactly(mockT, nil, a) {
+		t.Error("Exactly should return false")
+	}
+	if Exactly(mockT, a, nil) {
+		t.Error("Exactly should return false")
+	}
+
+}
+
+func TestNotEqual(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotEqual(mockT, "Hello World", "Hello World!") {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, 123, 1234) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, 123.5, 123.55) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, []byte("Hello World"), []byte("Hello World!")) {
+		t.Error("NotEqual should return true")
+	}
+	if !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return true")
+	}
+	funcA := func() int { return 23 }
+	funcB := func() int { return 42 }
+	if !NotEqual(mockT, funcA, funcB) {
+		t.Error("NotEqual should return true")
+	}
+
+	if NotEqual(mockT, "Hello World", "Hello World") {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, 123, 123) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, 123.5, 123.5) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, []byte("Hello World"), []byte("Hello World")) {
+		t.Error("NotEqual should return false")
+	}
+	if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return false")
+	}
+}
+
+type A struct {
+	Name, Value string
+}
+
+func TestContains(t *testing.T) {
+
+	mockT := new(testing.T)
+	list := []string{"Foo", "Bar"}
+	complexList := []*A{
+		{"b", "c"},
+		{"d", "e"},
+		{"g", "h"},
+		{"j", "k"},
+	}
+
+	if !Contains(mockT, "Hello World", "Hello") {
+		t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+	}
+	if Contains(mockT, "Hello World", "Salut") {
+		t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+	}
+
+	if !Contains(mockT, list, "Bar") {
+		t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Bar\"")
+	}
+	if Contains(mockT, list, "Salut") {
+		t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+	}
+	if !Contains(mockT, complexList, &A{"g", "h"}) {
+		t.Error("Contains should return true: complexList contains {\"g\", \"h\"}")
+	}
+	if Contains(mockT, complexList, &A{"g", "e"}) {
+		t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
+	}
+}
+
+func TestNotContains(t *testing.T) {
+
+	mockT := new(testing.T)
+	list := []string{"Foo", "Bar"}
+
+	if !NotContains(mockT, "Hello World", "Hello!") {
+		t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+	}
+	if NotContains(mockT, "Hello World", "Hello") {
+		t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+	}
+
+	if !NotContains(mockT, list, "Foo!") {
+		t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+	}
+	if NotContains(mockT, list, "Foo") {
+		t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+
+}
+
+func Test_includeElement(t *testing.T) {
+
+	list1 := []string{"Foo", "Bar"}
+	list2 := []int{1, 2}
+
+	ok, found := includeElement("Hello World", "World")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Foo")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Bar")
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list2, 1)
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list2, 2)
+	True(t, ok)
+	True(t, found)
+
+	ok, found = includeElement(list1, "Foo!")
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(list2, 3)
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(list2, "1")
+	True(t, ok)
+	False(t, found)
+
+	ok, found = includeElement(1433, "1")
+	False(t, ok)
+	False(t, found)
+
+}
+
+func TestCondition(t *testing.T) {
+	mockT := new(testing.T)
+
+	if !Condition(mockT, func() bool { return true }, "Truth") {
+		t.Error("Condition should return true")
+	}
+
+	if Condition(mockT, func() bool { return false }, "Lie") {
+		t.Error("Condition should return false")
+	}
+
+}
+
+func TestDidPanic(t *testing.T) {
+
+	if funcDidPanic, _ := didPanic(func() {
+		panic("Panic!")
+	}); !funcDidPanic {
+		t.Error("didPanic should return true")
+	}
+
+	if funcDidPanic, _ := didPanic(func() {
+	}); funcDidPanic {
+		t.Error("didPanic should return false")
+	}
+
+}
+
+func TestPanics(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !Panics(mockT, func() {
+		panic("Panic!")
+	}) {
+		t.Error("Panics should return true")
+	}
+
+	if Panics(mockT, func() {
+	}) {
+		t.Error("Panics should return false")
+	}
+
+}
+
+func TestNotPanics(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	if !NotPanics(mockT, func() {
+	}) {
+		t.Error("NotPanics should return true")
+	}
+
+	if NotPanics(mockT, func() {
+		panic("Panic!")
+	}) {
+		t.Error("NotPanics should return false")
+	}
+
+}
+
+func TestNoError(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+
+	True(t, NoError(mockT, err), "NoError should return True for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+
+	False(t, NoError(mockT, err), "NoError with error should return False")
+
+}
+
+func TestError(t *testing.T) {
+
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+
+	False(t, Error(mockT, err), "Error should return False for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+
+	True(t, Error(mockT, err), "Error with error should return True")
+
+}
+
+func TestEqualError(t *testing.T) {
+	mockT := new(testing.T)
+
+	// start with a nil error
+	var err error
+	False(t, EqualError(mockT, err, ""),
+		"EqualError should return false for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+	False(t, EqualError(mockT, err, "Not some error"),
+		"EqualError should return false for different error string")
+	True(t, EqualError(mockT, err, "some error"),
+		"EqualError should return true")
+}
+
+func Test_isEmpty(t *testing.T) {
+
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	True(t, isEmpty(""))
+	True(t, isEmpty(nil))
+	True(t, isEmpty([]string{}))
+	True(t, isEmpty(0))
+	True(t, isEmpty(int32(0)))
+	True(t, isEmpty(int64(0)))
+	True(t, isEmpty(false))
+	True(t, isEmpty(map[string]string{}))
+	True(t, isEmpty(new(time.Time)))
+	True(t, isEmpty(make(chan struct{})))
+	False(t, isEmpty("something"))
+	False(t, isEmpty(errors.New("something")))
+	False(t, isEmpty([]string{"something"}))
+	False(t, isEmpty(1))
+	False(t, isEmpty(true))
+	False(t, isEmpty(map[string]string{"Hello": "World"}))
+	False(t, isEmpty(chWithValue))
+
+}
+
+func TestEmpty(t *testing.T) {
+
+	mockT := new(testing.T)
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	True(t, Empty(mockT, ""), "Empty string is empty")
+	True(t, Empty(mockT, nil), "Nil is empty")
+	True(t, Empty(mockT, []string{}), "Empty string array is empty")
+	True(t, Empty(mockT, 0), "Zero int value is empty")
+	True(t, Empty(mockT, false), "False value is empty")
+	True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty")
+
+	False(t, Empty(mockT, "something"), "Non Empty string is not empty")
+	False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
+	False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty")
+	False(t, Empty(mockT, 1), "Non-zero int value is not empty")
+	False(t, Empty(mockT, true), "True value is not empty")
+	False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func TestNotEmpty(t *testing.T) {
+
+	mockT := new(testing.T)
+	chWithValue := make(chan struct{}, 1)
+	chWithValue <- struct{}{}
+
+	False(t, NotEmpty(mockT, ""), "Empty string is empty")
+	False(t, NotEmpty(mockT, nil), "Nil is empty")
+	False(t, NotEmpty(mockT, []string{}), "Empty string array is empty")
+	False(t, NotEmpty(mockT, 0), "Zero int value is empty")
+	False(t, NotEmpty(mockT, false), "False value is empty")
+	False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty")
+
+	True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty")
+	True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty")
+	True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty")
+	True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty")
+	True(t, NotEmpty(mockT, true), "True value is not empty")
+	True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func Test_getLen(t *testing.T) {
+	falseCases := []interface{}{
+		nil,
+		0,
+		true,
+		false,
+		'A',
+		struct{}{},
+	}
+	for _, v := range falseCases {
+		ok, l := getLen(v)
+		False(t, ok, "Expected getLen fail to get length of %#v", v)
+		Equal(t, 0, l, "getLen should return 0 for %#v", v)
+	}
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+	trueCases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range trueCases {
+		ok, l := getLen(c.v)
+		True(t, ok, "Expected getLen success to get length of %#v", c.v)
+		Equal(t, c.l, l)
+	}
+}
+
+func TestLen(t *testing.T) {
+	mockT := new(testing.T)
+
+	False(t, Len(mockT, nil, 0), "nil does not have length")
+	False(t, Len(mockT, 0, 0), "int does not have length")
+	False(t, Len(mockT, true, 0), "true does not have length")
+	False(t, Len(mockT, false, 0), "false does not have length")
+	False(t, Len(mockT, 'A', 0), "Rune does not have length")
+	False(t, Len(mockT, struct{}{}, 0), "Struct does not have length")
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+
+	cases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range cases {
+		True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+
+	cases = []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 4},
+		{[...]int{1, 2, 3}, 2},
+		{"ABC", 2},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 4},
+		{ch, 2},
+
+		{[]int{}, 1},
+		{map[int]int{}, 1},
+		{make(chan int), 1},
+
+		{[]int(nil), 1},
+		{map[int]int(nil), 1},
+		{(chan int)(nil), 1},
+	}
+
+	for _, c := range cases {
+		False(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+}
+
+func TestWithinDuration(t *testing.T) {
+
+	mockT := new(testing.T)
+	a := time.Now()
+	b := a.Add(10 * time.Second)
+
+	True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+	True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+	False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+	False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDelta(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+	True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+	True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1")
+	False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+	False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+	False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail")
+	False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail")
+	False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail")
+
+	cases := []struct {
+		a, b  interface{}
+		delta float64
+	}{
+		{uint8(2), uint8(1), 1},
+		{uint16(2), uint16(1), 1},
+		{uint32(2), uint32(1), 1},
+		{uint64(2), uint64(1), 1},
+
+		{int(2), int(1), 1},
+		{int8(2), int8(1), 1},
+		{int16(2), int16(1), 1},
+		{int32(2), int32(1), 1},
+		{int64(2), int64(1), 1},
+
+		{float32(2), float32(1), 1},
+		{float64(2), float64(1), 1},
+	}
+
+	for _, tc := range cases {
+		True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+	}
+}
+
+func TestInDeltaSlice(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InDeltaSlice(mockT,
+		[]float64{1.001, 0.999},
+		[]float64{1, 1},
+		0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1")
+
+	True(t, InDeltaSlice(mockT,
+		[]float64{1, 2},
+		[]float64{0, 3},
+		1), "{1, 2} is element-wise close to {0, 3} in delta=1")
+
+	False(t, InDeltaSlice(mockT,
+		[]float64{1, 2},
+		[]float64{0, 3},
+		0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1")
+
+	False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestInEpsilon(t *testing.T) {
+	mockT := new(testing.T)
+
+	cases := []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), uint16(2), .001},
+		{2.1, 2.2, 0.1},
+		{2.2, 2.1, 0.1},
+		{-2.1, -2.2, 0.1},
+		{-2.2, -2.1, 0.1},
+		{uint64(100), uint8(101), 0.01},
+		{0.1, -0.1, 2},
+	}
+
+	for _, tc := range cases {
+		True(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+	cases = []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), int16(-2), .001},
+		{uint64(100), uint8(102), 0.01},
+		{2.1, 2.2, 0.001},
+		{2.2, 2.1, 0.001},
+		{2.1, -2.2, 1},
+		{2.1, "bla-bla", 0},
+		{0.1, -0.1, 1.99},
+	}
+
+	for _, tc := range cases {
+		False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+}
+
+func TestInEpsilonSlice(t *testing.T) {
+	mockT := new(testing.T)
+
+	True(t, InEpsilonSlice(mockT,
+		[]float64{2.2, 2.0},
+		[]float64{2.1, 2.1},
+		0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06")
+
+	False(t, InEpsilonSlice(mockT,
+		[]float64{2.2, 2.0},
+		[]float64{2.1, 2.1},
+		0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04")
+
+	False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestRegexp(t *testing.T) {
+	mockT := new(testing.T)
+
+	cases := []struct {
+		rx, str string
+	}{
+		{"^start", "start of the line"},
+		{"end$", "in the end"},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+	}
+
+	for _, tc := range cases {
+		True(t, Regexp(mockT, tc.rx, tc.str))
+		True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+		False(t, NotRegexp(mockT, tc.rx, tc.str))
+		False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+	}
+
+	cases = []struct {
+		rx, str string
+	}{
+		{"^asdfastart", "Not the start of the line"},
+		{"end$", "in the end."},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+	}
+
+	for _, tc := range cases {
+		False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+		False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+		True(t, NotRegexp(mockT, tc.rx, tc.str))
+		True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+	}
+}

+ 154 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/doc.go

@@ -0,0 +1,154 @@
+// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
+//
+// Example Usage
+//
+// The following is a complete example using assert in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// if you assert many times, use the below:
+//
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//      assert := assert.New(t)
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(a, b, "The two words should be the same.")
+//    }
+//
+// Assertions
+//
+// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
+// All assertion functions take, as the first argument, the `*testing.T` object provided by the
+// testing framework. This allows the assertion funcs to write the failings and other details to
+// the correct place.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+//
+// Here is an overview of the assert functions:
+//
+//    assert.Equal(t, expected, actual [, message [, format-args]])
+//
+//    assert.EqualValues(t, expected, actual [, message [, format-args]])
+//
+//    assert.NotEqual(t, notExpected, actual [, message [, format-args]])
+//
+//    assert.True(t, actualBool [, message [, format-args]])
+//
+//    assert.False(t, actualBool [, message [, format-args]])
+//
+//    assert.Nil(t, actualObject [, message [, format-args]])
+//
+//    assert.NotNil(t, actualObject [, message [, format-args]])
+//
+//    assert.Empty(t, actualObject [, message [, format-args]])
+//
+//    assert.NotEmpty(t, actualObject [, message [, format-args]])
+//
+//    assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
+//
+//    assert.Error(t, errorObject [, message [, format-args]])
+//
+//    assert.NoError(t, errorObject [, message [, format-args]])
+//
+//    assert.EqualError(t, theError, errString [, message [, format-args]])
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
+//
+//    assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
+//
+//    assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.Panics(t, func(){
+//
+//	    // call code that should panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.NotPanics(t, func(){
+//
+//	    // call code that should not panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
+//
+//    assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
+//
+//    assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
+//
+// assert package contains Assertions object. it has assertion methods.
+//
+// Here is an overview of the assert functions:
+//    assert.Equal(expected, actual [, message [, format-args]])
+//
+//    assert.EqualValues(expected, actual [, message [, format-args]])
+//
+//    assert.NotEqual(notExpected, actual [, message [, format-args]])
+//
+//    assert.True(actualBool [, message [, format-args]])
+//
+//    assert.False(actualBool [, message [, format-args]])
+//
+//    assert.Nil(actualObject [, message [, format-args]])
+//
+//    assert.NotNil(actualObject [, message [, format-args]])
+//
+//    assert.Empty(actualObject [, message [, format-args]])
+//
+//    assert.NotEmpty(actualObject [, message [, format-args]])
+//
+//    assert.Len(actualObject, expectedLength, [, message [, format-args]])
+//
+//    assert.Error(errorObject [, message [, format-args]])
+//
+//    assert.NoError(errorObject [, message [, format-args]])
+//
+//    assert.EqualError(theError, errString [, message [, format-args]])
+//
+//    assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
+//
+//    assert.IsType(expectedObject, actualObject [, message [, format-args]])
+//
+//    assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
+//
+//    assert.Panics(func(){
+//
+//	    // call code that should panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.NotPanics(func(){
+//
+//	    // call code that should not panic
+//
+//    } [, message [, format-args]])
+//
+//    assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
+//
+//    assert.InDelta(numA, numB, delta, [, message [, format-args]])
+//
+//    assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
+package assert

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/errors.go

@@ -0,0 +1,10 @@
+package assert
+
+import (
+	"errors"
+)
+
+// AnError is an error instance useful for testing.  If the code does not care
+// about error specifics, and only needs to return the error for example, this
+// error should be used to make the test code more readable.
+var AnError = errors.New("assert.AnError general error for testing")

+ 265 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go

@@ -0,0 +1,265 @@
+package assert
+
+import "time"
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+	return Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	return Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	return IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(123, 123, "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactly asserts that two objects are equal is value and type.
+//
+//    assert.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(err, "err should be something")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+	return NotNil(a.t, object, msgAndArgs...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(err, "err should be nothing")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+	return Nil(a.t, object, msgAndArgs...)
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or a
+// slice with len == 0.
+//
+// assert.Empty(obj)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+	return Empty(a.t, object, msgAndArgs...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or a
+// slice with len == 0.
+//
+// if assert.NotEmpty(obj) {
+//   assert.Equal("two", obj[1])
+// }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+	return NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(mySlice, 3, "The size of slice is not 3")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+	return Len(a.t, object, length, msgAndArgs...)
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(myBool, "myBool should be true")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+	return True(a.t, value, msgAndArgs...)
+}
+
+// False asserts that the specified value is true.
+//
+//    assert.False(myBool, "myBool should be false")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+	return False(a.t, value, msgAndArgs...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(obj1, obj2, "two objects shouldn't be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	return NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// Contains asserts that the specified string contains the specified substring.
+//
+//    assert.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) bool {
+	return Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContains asserts that the specified string does NOT contain the specified substring.
+//
+//    assert.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) bool {
+	return NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+	return Condition(a.t, comp, msgAndArgs...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	return Panics(a.t, f, msgAndArgs...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	return NotPanics(a.t, f, msgAndArgs...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+	return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	return InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(err) {
+//	   assert.Equal(actualObj, expectedObj)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) bool {
+	return NoError(a.t, theError, msgAndArgs...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(err, "An error was expected") {
+//	   assert.Equal(err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) bool {
+	return Error(a.t, theError, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(err, "An error was expected") {
+//	   assert.Equal(err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+	return EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	return Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	return NotRegexp(a.t, rx, str, msgAndArgs...)
+}

+ 511 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions_test.go

@@ -0,0 +1,511 @@
+package assert
+
+import (
+	"errors"
+	"regexp"
+	"testing"
+	"time"
+)
+
+func TestImplementsWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+		t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+	}
+	if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+		t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+	}
+}
+
+func TestIsTypeWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+		t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+	}
+	if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+		t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+	}
+
+}
+
+func TestEqualWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Equal("Hello World", "Hello World") {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(123, 123) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(123.5, 123.5) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal([]byte("Hello World"), []byte("Hello World")) {
+		t.Error("Equal should return true")
+	}
+	if !assert.Equal(nil, nil) {
+		t.Error("Equal should return true")
+	}
+}
+
+func TestEqualValuesWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.EqualValues(uint32(10), int32(10)) {
+		t.Error("EqualValues should return true")
+	}
+}
+
+func TestNotNilWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.NotNil(new(AssertionTesterConformingObject)) {
+		t.Error("NotNil should return true: object is not nil")
+	}
+	if assert.NotNil(nil) {
+		t.Error("NotNil should return false: object is nil")
+	}
+
+}
+
+func TestNilWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.Nil(nil) {
+		t.Error("Nil should return true: object is nil")
+	}
+	if assert.Nil(new(AssertionTesterConformingObject)) {
+		t.Error("Nil should return false: object is not nil")
+	}
+
+}
+
+func TestTrueWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.True(true) {
+		t.Error("True should return true")
+	}
+	if assert.True(false) {
+		t.Error("True should return false")
+	}
+
+}
+
+func TestFalseWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	if !assert.False(false) {
+		t.Error("False should return true")
+	}
+	if assert.False(true) {
+		t.Error("False should return false")
+	}
+
+}
+
+func TestExactlyWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	a := float32(1)
+	b := float64(1)
+	c := float32(1)
+	d := float32(2)
+
+	if assert.Exactly(a, b) {
+		t.Error("Exactly should return false")
+	}
+	if assert.Exactly(a, d) {
+		t.Error("Exactly should return false")
+	}
+	if !assert.Exactly(a, c) {
+		t.Error("Exactly should return true")
+	}
+
+	if assert.Exactly(nil, a) {
+		t.Error("Exactly should return false")
+	}
+	if assert.Exactly(a, nil) {
+		t.Error("Exactly should return false")
+	}
+
+}
+
+func TestNotEqualWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.NotEqual("Hello World", "Hello World!") {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(123, 1234) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(123.5, 123.55) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) {
+		t.Error("NotEqual should return true")
+	}
+	if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) {
+		t.Error("NotEqual should return true")
+	}
+}
+
+func TestContainsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+	list := []string{"Foo", "Bar"}
+
+	if !assert.Contains("Hello World", "Hello") {
+		t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+	}
+	if assert.Contains("Hello World", "Salut") {
+		t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+	}
+
+	if !assert.Contains(list, "Foo") {
+		t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+	if assert.Contains(list, "Salut") {
+		t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+	}
+
+}
+
+func TestNotContainsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+	list := []string{"Foo", "Bar"}
+
+	if !assert.NotContains("Hello World", "Hello!") {
+		t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+	}
+	if assert.NotContains("Hello World", "Hello") {
+		t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+	}
+
+	if !assert.NotContains(list, "Foo!") {
+		t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+	}
+	if assert.NotContains(list, "Foo") {
+		t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+	}
+
+}
+
+func TestConditionWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.Condition(func() bool { return true }, "Truth") {
+		t.Error("Condition should return true")
+	}
+
+	if assert.Condition(func() bool { return false }, "Lie") {
+		t.Error("Condition should return false")
+	}
+
+}
+
+func TestDidPanicWrapper(t *testing.T) {
+
+	if funcDidPanic, _ := didPanic(func() {
+		panic("Panic!")
+	}); !funcDidPanic {
+		t.Error("didPanic should return true")
+	}
+
+	if funcDidPanic, _ := didPanic(func() {
+	}); funcDidPanic {
+		t.Error("didPanic should return false")
+	}
+
+}
+
+func TestPanicsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.Panics(func() {
+		panic("Panic!")
+	}) {
+		t.Error("Panics should return true")
+	}
+
+	if assert.Panics(func() {
+	}) {
+		t.Error("Panics should return false")
+	}
+
+}
+
+func TestNotPanicsWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	if !assert.NotPanics(func() {
+	}) {
+		t.Error("NotPanics should return true")
+	}
+
+	if assert.NotPanics(func() {
+		panic("Panic!")
+	}) {
+		t.Error("NotPanics should return false")
+	}
+
+}
+
+func TestNoErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+
+	assert.True(mockAssert.NoError(err), "NoError should return True for nil arg")
+
+	// now set an error
+	err = errors.New("Some error")
+
+	assert.False(mockAssert.NoError(err), "NoError with error should return False")
+
+}
+
+func TestErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+
+	assert.False(mockAssert.Error(err), "Error should return False for nil arg")
+
+	// now set an error
+	err = errors.New("Some error")
+
+	assert.True(mockAssert.Error(err), "Error with error should return True")
+
+}
+
+func TestEqualErrorWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	// start with a nil error
+	var err error
+	assert.False(mockAssert.EqualError(err, ""),
+		"EqualError should return false for nil arg")
+
+	// now set an error
+	err = errors.New("some error")
+	assert.False(mockAssert.EqualError(err, "Not some error"),
+		"EqualError should return false for different error string")
+	assert.True(mockAssert.EqualError(err, "some error"),
+		"EqualError should return true")
+}
+
+func TestEmptyWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.True(mockAssert.Empty(""), "Empty string is empty")
+	assert.True(mockAssert.Empty(nil), "Nil is empty")
+	assert.True(mockAssert.Empty([]string{}), "Empty string array is empty")
+	assert.True(mockAssert.Empty(0), "Zero int value is empty")
+	assert.True(mockAssert.Empty(false), "False value is empty")
+
+	assert.False(mockAssert.Empty("something"), "Non Empty string is not empty")
+	assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty")
+	assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty")
+	assert.False(mockAssert.Empty(1), "Non-zero int value is not empty")
+	assert.False(mockAssert.Empty(true), "True value is not empty")
+
+}
+
+func TestNotEmptyWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.False(mockAssert.NotEmpty(""), "Empty string is empty")
+	assert.False(mockAssert.NotEmpty(nil), "Nil is empty")
+	assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty")
+	assert.False(mockAssert.NotEmpty(0), "Zero int value is empty")
+	assert.False(mockAssert.NotEmpty(false), "False value is empty")
+
+	assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty")
+	assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty")
+	assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty")
+	assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty")
+	assert.True(mockAssert.NotEmpty(true), "True value is not empty")
+
+}
+
+func TestLenWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.False(mockAssert.Len(nil, 0), "nil does not have length")
+	assert.False(mockAssert.Len(0, 0), "int does not have length")
+	assert.False(mockAssert.Len(true, 0), "true does not have length")
+	assert.False(mockAssert.Len(false, 0), "false does not have length")
+	assert.False(mockAssert.Len('A', 0), "Rune does not have length")
+	assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length")
+
+	ch := make(chan int, 5)
+	ch <- 1
+	ch <- 2
+	ch <- 3
+
+	cases := []struct {
+		v interface{}
+		l int
+	}{
+		{[]int{1, 2, 3}, 3},
+		{[...]int{1, 2, 3}, 3},
+		{"ABC", 3},
+		{map[int]int{1: 2, 2: 4, 3: 6}, 3},
+		{ch, 3},
+
+		{[]int{}, 0},
+		{map[int]int{}, 0},
+		{make(chan int), 0},
+
+		{[]int(nil), 0},
+		{map[int]int(nil), 0},
+		{(chan int)(nil), 0},
+	}
+
+	for _, c := range cases {
+		assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l)
+	}
+}
+
+func TestWithinDurationWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+	a := time.Now()
+	b := a.Add(10 * time.Second)
+
+	assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+	assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+	assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+	assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDeltaWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+	True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+	True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1")
+	False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+	False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+	False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail")
+
+	cases := []struct {
+		a, b  interface{}
+		delta float64
+	}{
+		{uint8(2), uint8(1), 1},
+		{uint16(2), uint16(1), 1},
+		{uint32(2), uint32(1), 1},
+		{uint64(2), uint64(1), 1},
+
+		{int(2), int(1), 1},
+		{int8(2), int8(1), 1},
+		{int16(2), int16(1), 1},
+		{int32(2), int32(1), 1},
+		{int64(2), int64(1), 1},
+
+		{float32(2), float32(1), 1},
+		{float64(2), float64(1), 1},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+	}
+}
+
+func TestInEpsilonWrapper(t *testing.T) {
+	assert := New(new(testing.T))
+
+	cases := []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), uint16(2), .001},
+		{2.1, 2.2, 0.1},
+		{2.2, 2.1, 0.1},
+		{-2.1, -2.2, 0.1},
+		{-2.2, -2.1, 0.1},
+		{uint64(100), uint8(101), 0.01},
+		{0.1, -0.1, 2},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+
+	cases = []struct {
+		a, b    interface{}
+		epsilon float64
+	}{
+		{uint8(2), int16(-2), .001},
+		{uint64(100), uint8(102), 0.01},
+		{2.1, 2.2, 0.001},
+		{2.2, 2.1, 0.001},
+		{2.1, -2.2, 1},
+		{2.1, "bla-bla", 0},
+		{0.1, -0.1, 1.99},
+	}
+
+	for _, tc := range cases {
+		False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+	}
+}
+
+func TestRegexpWrapper(t *testing.T) {
+
+	assert := New(new(testing.T))
+
+	cases := []struct {
+		rx, str string
+	}{
+		{"^start", "start of the line"},
+		{"end$", "in the end"},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+	}
+
+	for _, tc := range cases {
+		True(t, assert.Regexp(tc.rx, tc.str))
+		True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+		False(t, assert.NotRegexp(tc.rx, tc.str))
+		False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+	}
+
+	cases = []struct {
+		rx, str string
+	}{
+		{"^asdfastart", "Not the start of the line"},
+		{"end$", "in the end."},
+		{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+	}
+
+	for _, tc := range cases {
+		False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+		False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+		True(t, assert.NotRegexp(tc.rx, tc.str))
+		True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+	}
+}

+ 157 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go

@@ -0,0 +1,157 @@
+package assert
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+)
+
+// httpCode is a helper that returns HTTP code of the response. It returns -1
+// if building a new request fails.
+func httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int {
+	w := httptest.NewRecorder()
+	req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
+	if err != nil {
+		return -1
+	}
+	handler(w, req)
+	return w.Code
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusOK && code <= http.StatusPartialContent
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	code := httpCode(handler, mode, url, values)
+	if code == -1 {
+		return false
+	}
+	return code >= http.StatusBadRequest
+}
+
+// HTTPBody is a helper that returns HTTP body of the response. It returns
+// empty string if building a new request fails.
+func HTTPBody(handler http.HandlerFunc, mode, url string, values url.Values) string {
+	w := httptest.NewRecorder()
+	req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
+	if err != nil {
+		return ""
+	}
+	handler(w, req)
+	return w.Body.String()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	body := HTTPBody(handler, mode, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if !contains {
+		Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
+	}
+
+	return contains
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	body := HTTPBody(handler, mode, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if contains {
+		Fail(t, "Expected response body for %s to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)
+	}
+
+	return !contains
+}
+
+//
+// Assertions Wrappers
+//
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPSuccess(a.t, handler, mode, url, values)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPRedirect(a.t, handler, mode, url, values)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool {
+	return HTTPError(a.t, handler, mode, url, values)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	return HTTPBodyContains(a.t, handler, mode, url, values, str)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
+	return HTTPBodyNotContains(a.t, handler, mode, url, values, str)
+}

+ 86 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions_test.go

@@ -0,0 +1,86 @@
+package assert
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func httpOK(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusOK)
+}
+
+func httpRedirect(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusTemporaryRedirect)
+}
+
+func httpError(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusInternalServerError)
+}
+
+func TestHTTPStatuses(t *testing.T) {
+	assert := New(t)
+	mockT := new(testing.T)
+
+	assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true)
+	assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false)
+	assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false)
+
+	assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false)
+	assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true)
+	assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false)
+
+	assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false)
+	assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false)
+	assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true)
+}
+
+func TestHTTPStatusesWrapper(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true)
+	assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false)
+
+	assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true)
+	assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false)
+
+	assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false)
+	assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true)
+}
+
+func httpHelloName(w http.ResponseWriter, r *http.Request) {
+	name := r.FormValue("name")
+	w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
+}
+
+func TestHttpBody(t *testing.T) {
+	assert := New(t)
+	mockT := new(testing.T)
+
+	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+}
+
+func TestHttpBodyWrappers(t *testing.T) {
+	assert := New(t)
+	mockAssert := New(new(testing.T))
+
+	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+	assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+}

+ 43 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go

@@ -0,0 +1,43 @@
+// Provides a system by which it is possible to mock your objects and verify calls are happening as expected.
+//
+// Example Usage
+//
+// The mock package provides an object, Mock, that tracks activity on another object.  It is usually
+// embedded into a test object as shown below:
+//
+//   type MyTestObject struct {
+//     // add a Mock object instance
+//     mock.Mock
+//
+//     // other fields go here as normal
+//   }
+//
+// When implementing the methods of an interface, you wire your functions up
+// to call the Mock.Called(args...) method, and return the appropriate values.
+//
+// For example, to mock a method that saves the name and age of a person and returns
+// the year of their birth or an error, you might write this:
+//
+//     func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
+//       args := o.Called(firstname, lastname, age)
+//       return args.Int(0), args.Error(1)
+//     }
+//
+// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
+// index position. Given this argument list:
+//
+//     (12, true, "Something")
+//
+// You could read them out strongly typed like this:
+//
+//     args.Int(0)
+//     args.Bool(1)
+//     args.String(2)
+//
+// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
+//
+//     return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
+//
+// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
+// cases you should check for nil first.
+package mock

+ 566 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go

@@ -0,0 +1,566 @@
+package mock
+
+import (
+	"fmt"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/objx"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"reflect"
+	"runtime"
+	"strings"
+	"sync"
+	"time"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Logf(format string, args ...interface{})
+	Errorf(format string, args ...interface{})
+}
+
+/*
+	Call
+*/
+
+// Call represents a method call and is used for setting expectations,
+// as well as recording activity.
+type Call struct {
+
+	// The name of the method that was or will be called.
+	Method string
+
+	// Holds the arguments of the method.
+	Arguments Arguments
+
+	// Holds the arguments that should be returned when
+	// this method is called.
+	ReturnArguments Arguments
+
+	// The number of times to return the return arguments when setting
+	// expectations. 0 means to always return the value.
+	Repeatability int
+
+	// Holds a channel that will be used to block the Return until it either
+	// recieves a message or is closed. nil means it returns immediately.
+	WaitFor <-chan time.Time
+
+	// Holds a handler used to manipulate arguments content that are passed by
+	// reference. It's useful when mocking methods such as unmarshalers or
+	// decoders.
+	Run func(Arguments)
+}
+
+// Mock is the workhorse used to track activity on another object.
+// For an example of its usage, refer to the "Example Usage" section at the top of this document.
+type Mock struct {
+
+	// The method name that is currently
+	// being referred to by the On method.
+	onMethodName string
+
+	// An array of the arguments that are
+	// currently being referred to by the On method.
+	onMethodArguments Arguments
+
+	// Represents the calls that are expected of
+	// an object.
+	ExpectedCalls []Call
+
+	// Holds the calls that were made to this mocked object.
+	Calls []Call
+
+	// TestData holds any data that might be useful for testing.  Testify ignores
+	// this data completely allowing you to do whatever you like with it.
+	testData objx.Map
+
+	mutex sync.Mutex
+}
+
+// TestData holds any data that might be useful for testing.  Testify ignores
+// this data completely allowing you to do whatever you like with it.
+func (m *Mock) TestData() objx.Map {
+
+	if m.testData == nil {
+		m.testData = make(objx.Map)
+	}
+
+	return m.testData
+}
+
+/*
+	Setting expectations
+*/
+
+// On starts a description of an expectation of the specified method
+// being called.
+//
+//     Mock.On("MyMethod", arg1, arg2)
+func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
+	m.onMethodName = methodName
+	m.onMethodArguments = arguments
+
+	for _, arg := range arguments {
+		if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
+			panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
+		}
+	}
+
+	return m
+}
+
+// Return finishes a description of an expectation of the method (and arguments)
+// specified in the most recent On method call.
+//
+//     Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2)
+func (m *Mock) Return(returnArguments ...interface{}) *Mock {
+	m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil})
+	return m
+}
+
+// Once indicates that that the mock should only return the value once.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
+func (m *Mock) Once() {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1
+}
+
+// Twice indicates that that the mock should only return the value twice.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
+func (m *Mock) Twice() {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2
+}
+
+// Times indicates that that the mock should only return the indicated number
+// of times.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
+func (m *Mock) Times(i int) {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i
+}
+
+// WaitUntil sets the channel that will block the mock's return until its closed
+// or a message is received.
+//
+//    Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
+func (m *Mock) WaitUntil(w <-chan time.Time) *Mock {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w
+	return m
+}
+
+// After sets how long to block until the call returns
+//
+//    Mock.On("MyMethod", arg1, arg2).After(time.Second)
+func (m *Mock) After(d time.Duration) *Mock {
+	return m.WaitUntil(time.After(d))
+}
+
+// Run sets a handler to be called before returning. It can be used when
+// mocking a method such as unmarshalers that takes a pointer to a struct and
+// sets properties in such struct
+//
+//    Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(function(args Arguments) {
+//    	arg := args.Get(0).(*map[string]interface{})
+//    	arg["foo"] = "bar"
+//    })
+func (m *Mock) Run(fn func(Arguments)) *Mock {
+	m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn
+	return m
+}
+
+/*
+	Recording and responding to activity
+*/
+
+func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
+	for i, call := range m.ExpectedCalls {
+		if call.Method == method && call.Repeatability > -1 {
+
+			_, diffCount := call.Arguments.Diff(arguments)
+			if diffCount == 0 {
+				return i, &call
+			}
+
+		}
+	}
+	return -1, nil
+}
+
+func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
+
+	diffCount := 0
+	var closestCall *Call = nil
+
+	for _, call := range m.ExpectedCalls {
+		if call.Method == method {
+
+			_, tempDiffCount := call.Arguments.Diff(arguments)
+			if tempDiffCount < diffCount || diffCount == 0 {
+				diffCount = tempDiffCount
+				closestCall = &call
+			}
+
+		}
+	}
+
+	if closestCall == nil {
+		return false, nil
+	}
+
+	return true, closestCall
+}
+
+func callString(method string, arguments Arguments, includeArgumentValues bool) string {
+
+	var argValsString string = ""
+	if includeArgumentValues {
+		var argVals []string
+		for argIndex, arg := range arguments {
+			argVals = append(argVals, fmt.Sprintf("%d: %v", argIndex, arg))
+		}
+		argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
+	}
+
+	return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
+}
+
+// Called tells the mock object that a method has been called, and gets an array
+// of arguments to return.  Panics if the call is unexpected (i.e. not preceeded by
+// appropriate .On .Return() calls)
+// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
+func (m *Mock) Called(arguments ...interface{}) Arguments {
+	defer m.mutex.Unlock()
+	m.mutex.Lock()
+
+	// get the calling function's name
+	pc, _, _, ok := runtime.Caller(1)
+	if !ok {
+		panic("Couldn't get the caller information")
+	}
+	functionPath := runtime.FuncForPC(pc).Name()
+	parts := strings.Split(functionPath, ".")
+	functionName := parts[len(parts)-1]
+
+	found, call := m.findExpectedCall(functionName, arguments...)
+
+	switch {
+	case found < 0:
+		// we have to fail here - because we don't know what to do
+		// as the return arguments.  This is because:
+		//
+		//   a) this is a totally unexpected call to this method,
+		//   b) the arguments are not what was expected, or
+		//   c) the developer has forgotten to add an accompanying On...Return pair.
+
+		closestFound, closestCall := m.findClosestCall(functionName, arguments...)
+
+		if closestFound {
+			panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true)))
+		} else {
+			panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
+		}
+	case call.Repeatability == 1:
+		call.Repeatability = -1
+		m.ExpectedCalls[found] = *call
+	case call.Repeatability > 1:
+		call.Repeatability -= 1
+		m.ExpectedCalls[found] = *call
+	}
+
+	// add the call
+	m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil})
+
+	// block if specified
+	if call.WaitFor != nil {
+		<-call.WaitFor
+	}
+
+	if call.Run != nil {
+		call.Run(arguments)
+	}
+
+	return call.ReturnArguments
+
+}
+
+/*
+	Assertions
+*/
+
+// AssertExpectationsForObjects asserts that everything specified with On and Return
+// of the specified objects was in fact called as expected.
+//
+// Calls may have occurred in any order.
+func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
+	var success bool = true
+	for _, obj := range testObjects {
+		mockObj := obj.(Mock)
+		success = success && mockObj.AssertExpectations(t)
+	}
+	return success
+}
+
+// AssertExpectations asserts that everything specified with On and Return was
+// in fact called as expected.  Calls may have occurred in any order.
+func (m *Mock) AssertExpectations(t TestingT) bool {
+
+	var somethingMissing bool = false
+	var failedExpectations int = 0
+
+	// iterate through each expectation
+	for _, expectedCall := range m.ExpectedCalls {
+		switch {
+		case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments):
+			somethingMissing = true
+			failedExpectations++
+			t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+		case expectedCall.Repeatability > 0:
+			somethingMissing = true
+			failedExpectations++
+		default:
+			t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+		}
+	}
+
+	if somethingMissing {
+		t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(m.ExpectedCalls)-failedExpectations, len(m.ExpectedCalls), failedExpectations, assert.CallerInfo())
+	}
+
+	return !somethingMissing
+}
+
+// AssertNumberOfCalls asserts that the method was called expectedCalls times.
+func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
+	var actualCalls int = 0
+	for _, call := range m.Calls {
+		if call.Method == methodName {
+			actualCalls++
+		}
+	}
+	return assert.Equal(t, actualCalls, expectedCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
+}
+
+// AssertCalled asserts that the method was called.
+func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+	if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
+		t.Logf("%v", m.ExpectedCalls)
+		return false
+	}
+	return true
+}
+
+// AssertNotCalled asserts that the method was not called.
+func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+	if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
+		t.Logf("%v", m.ExpectedCalls)
+		return false
+	}
+	return true
+}
+
+func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
+	for _, call := range m.Calls {
+		if call.Method == methodName {
+
+			_, differences := Arguments(expected).Diff(call.Arguments)
+
+			if differences == 0 {
+				// found the expected call
+				return true
+			}
+
+		}
+	}
+	// we didn't find the expected call
+	return false
+}
+
+/*
+	Arguments
+*/
+
+// Arguments holds an array of method arguments or return values.
+type Arguments []interface{}
+
+const (
+	// The "any" argument.  Used in Diff and Assert when
+	// the argument being tested shouldn't be taken into consideration.
+	Anything string = "mock.Anything"
+)
+
+// AnythingOfTypeArgument is a string that contains the type of an argument
+// for use when type checking.  Used in Diff and Assert.
+type AnythingOfTypeArgument string
+
+// AnythingOfType returns an AnythingOfTypeArgument object containing the
+// name of the type to check for.  Used in Diff and Assert.
+//
+// For example:
+//	Assert(t, AnythingOfType("string"), AnythingOfType("int"))
+func AnythingOfType(t string) AnythingOfTypeArgument {
+	return AnythingOfTypeArgument(t)
+}
+
+// Get Returns the argument at the specified index.
+func (args Arguments) Get(index int) interface{} {
+	if index+1 > len(args) {
+		panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
+	}
+	return args[index]
+}
+
+// Is gets whether the objects match the arguments specified.
+func (args Arguments) Is(objects ...interface{}) bool {
+	for i, obj := range args {
+		if obj != objects[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// Diff gets a string describing the differences between the arguments
+// and the specified objects.
+//
+// Returns the diff string and number of differences found.
+func (args Arguments) Diff(objects []interface{}) (string, int) {
+
+	var output string = "\n"
+	var differences int
+
+	var maxArgCount int = len(args)
+	if len(objects) > maxArgCount {
+		maxArgCount = len(objects)
+	}
+
+	for i := 0; i < maxArgCount; i++ {
+		var actual, expected interface{}
+
+		if len(objects) <= i {
+			actual = "(Missing)"
+		} else {
+			actual = objects[i]
+		}
+
+		if len(args) <= i {
+			expected = "(Missing)"
+		} else {
+			expected = args[i]
+		}
+
+		if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
+
+			// type checking
+			if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
+				// not match
+				differences++
+				output = fmt.Sprintf("%s\t%d: \u274C  type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual)
+			}
+
+		} else {
+
+			// normal checking
+
+			if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
+				// match
+				output = fmt.Sprintf("%s\t%d: \u2705  %s == %s\n", output, i, actual, expected)
+			} else {
+				// not match
+				differences++
+				output = fmt.Sprintf("%s\t%d: \u274C  %s != %s\n", output, i, actual, expected)
+			}
+		}
+
+	}
+
+	if differences == 0 {
+		return "No differences.", differences
+	}
+
+	return output, differences
+
+}
+
+// Assert compares the arguments with the specified objects and fails if
+// they do not exactly match.
+func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
+
+	// get the differences
+	diff, diffCount := args.Diff(objects)
+
+	if diffCount == 0 {
+		return true
+	}
+
+	// there are differences... report them...
+	t.Logf(diff)
+	t.Errorf("%sArguments do not match.", assert.CallerInfo())
+
+	return false
+
+}
+
+// String gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+//
+// If no index is provided, String() returns a complete string representation
+// of the arguments.
+func (args Arguments) String(indexOrNil ...int) string {
+
+	if len(indexOrNil) == 0 {
+		// normal String() method - return a string representation of the args
+		var argsStr []string
+		for _, arg := range args {
+			argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
+		}
+		return strings.Join(argsStr, ",")
+	} else if len(indexOrNil) == 1 {
+		// Index has been specified - get the argument at that index
+		var index int = indexOrNil[0]
+		var s string
+		var ok bool
+		if s, ok = args.Get(index).(string); !ok {
+			panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
+		}
+		return s
+	}
+
+	panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String.  Must be 0 or 1, not %d", len(indexOrNil)))
+
+}
+
+// Int gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Int(index int) int {
+	var s int
+	var ok bool
+	if s, ok = args.Get(index).(int); !ok {
+		panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}
+
+// Error gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Error(index int) error {
+	obj := args.Get(index)
+	var s error
+	var ok bool
+	if obj == nil {
+		return nil
+	}
+	if s, ok = obj.(error); !ok {
+		panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}
+
+// Bool gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Bool(index int) bool {
+	var s bool
+	var ok bool
+	if s, ok = args.Get(index).(bool); !ok {
+		panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+	}
+	return s
+}

+ 843 - 0
libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock_test.go

@@ -0,0 +1,843 @@
+package mock
+
+import (
+	"errors"
+	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"testing"
+	"time"
+)
+
+/*
+	Test objects
+*/
+
+// ExampleInterface represents an example interface.
+type ExampleInterface interface {
+	TheExampleMethod(a, b, c int) (int, error)
+}
+
+// TestExampleImplementation is a test implementation of ExampleInterface
+type TestExampleImplementation struct {
+	Mock
+}
+
+func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
+	args := i.Called(a, b, c)
+	return args.Int(0), errors.New("Whoops")
+}
+
+func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
+	i.Called(yesorno)
+}
+
+type ExampleType struct {
+	ran bool
+}
+
+func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
+	args := i.Called(et)
+	return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
+	args := i.Called(fn)
+	return args.Error(0)
+}
+
+type ExampleFuncType func(string) error
+
+func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
+	args := i.Called(fn)
+	return args.Error(0)
+}
+
+/*
+	Mock
+*/
+
+func Test_Mock_TestData(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	if assert.NotNil(t, mockedService.TestData()) {
+
+		mockedService.TestData().Set("something", 123)
+		assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
+
+	}
+
+}
+
+func Test_Mock_On(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod"), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
+
+}
+
+func Test_Mock_On_WithArgs(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", 1, 2, 3), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
+	assert.Equal(t, 1, mockedService.onMethodArguments[0])
+	assert.Equal(t, 2, mockedService.onMethodArguments[1])
+	assert.Equal(t, 3, mockedService.onMethodArguments[2])
+
+}
+
+func Test_Mock_On_WithFuncArg(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethodFunc", AnythingOfType("func(string) error")).Return(nil), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethodFunc", mockedService.onMethodName)
+	assert.Equal(t, AnythingOfType("func(string) error"), mockedService.onMethodArguments[0])
+
+	fn := func(string) error { return nil }
+	mockedService.TheExampleMethodFunc(fn)
+
+}
+
+func Test_Mock_On_WithFuncPanics(t *testing.T) {
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Panics(t, func() {
+		mockedService.On("TheExampleMethodFunc", func(string) error { return nil })
+	})
+}
+
+func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).Return(nil), &mockedService.Mock)
+	assert.Equal(t, "TheExampleMethodFuncType", mockedService.onMethodName)
+	assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), mockedService.onMethodArguments[0])
+
+	fn := func(string) error { return nil }
+	mockedService.TheExampleMethodFuncType(fn)
+
+}
+
+func Test_Mock_Return(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_WaitUntil(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+	ch := time.After(time.Second)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).WaitUntil(ch), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.Equal(t, ch, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_After(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).After(time.Second), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.NotEqual(t, nil, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Run(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.Mock.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Run(func(args Arguments) {
+		arg := args.Get(0).(*ExampleType)
+		arg.ran = true
+	}), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
+		call := mockedService.Mock.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod3", call.Method)
+		assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0])
+		assert.Equal(t, nil, call.ReturnArguments[0])
+		assert.Equal(t, 0, call.Repeatability)
+		assert.NotEqual(t, nil, call.WaitFor)
+		assert.NotNil(t, call.Run)
+
+	}
+
+	et := ExampleType{}
+	assert.Equal(t, false, et.ran)
+	mockedService.TheExampleMethod3(&et)
+	assert.Equal(t, true, et.ran)
+
+}
+
+func Test_Mock_Return_Once(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Once()
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 1, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Twice(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Twice()
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 2, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Times(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Times(5)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 1, call.ReturnArguments[0])
+		assert.Equal(t, "two", call.ReturnArguments[1])
+		assert.Equal(t, true, call.ReturnArguments[2])
+		assert.Equal(t, 5, call.Repeatability)
+		assert.Nil(t, call.WaitFor)
+
+	}
+
+}
+
+func Test_Mock_Return_Nothing(t *testing.T) {
+
+	// make a test impl object
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(), &mockedService.Mock)
+
+	// ensure the call was created
+	if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
+		call := mockedService.ExpectedCalls[0]
+
+		assert.Equal(t, "TheExampleMethod", call.Method)
+		assert.Equal(t, "A", call.Arguments[0])
+		assert.Equal(t, "B", call.Arguments[1])
+		assert.Equal(t, true, call.Arguments[2])
+		assert.Equal(t, 0, len(call.ReturnArguments))
+
+	}
+
+}
+
+func Test_Mock_findExpectedCall(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two")
+	m.On("Two", 3).Return("three")
+
+	f, c := m.findExpectedCall("Two", 3)
+
+	if assert.Equal(t, 2, f) {
+		if assert.NotNil(t, c) {
+			assert.Equal(t, "Two", c.Method)
+			assert.Equal(t, 3, c.Arguments[0])
+			assert.Equal(t, "three", c.ReturnArguments[0])
+		}
+	}
+
+}
+
+func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two")
+	m.On("Two", 3).Return("three")
+
+	f, _ := m.findExpectedCall("Two")
+
+	assert.Equal(t, -1, f)
+
+}
+
+func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
+
+	m := new(Mock)
+	m.On("One", 1).Return("one")
+	m.On("Two", 2).Return("two").Once()
+	m.On("Two", 3).Return("three").Twice()
+	m.On("Two", 3).Return("three").Times(8)
+
+	f, c := m.findExpectedCall("Two", 3)
+
+	if assert.Equal(t, 2, f) {
+		if assert.NotNil(t, c) {
+			assert.Equal(t, "Two", c.Method)
+			assert.Equal(t, 3, c.Arguments[0])
+			assert.Equal(t, "three", c.ReturnArguments[0])
+		}
+	}
+
+}
+
+func Test_callString(t *testing.T) {
+
+	assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
+
+}
+
+func Test_Mock_Called(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true)
+
+	returnArguments := mockedService.Called(1, 2, 3)
+
+	if assert.Equal(t, 1, len(mockedService.Calls)) {
+		assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments)) {
+		assert.Equal(t, 5, returnArguments[0])
+		assert.Equal(t, "6", returnArguments[1])
+		assert.Equal(t, true, returnArguments[2])
+	}
+
+}
+
+func asyncCall(m *Mock, ch chan Arguments) {
+	ch <- m.Called(1, 2, 3)
+}
+
+func Test_Mock_Called_blocks(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond)
+
+	ch := make(chan Arguments)
+
+	go asyncCall(&mockedService.Mock, ch)
+
+	select {
+	case <-ch:
+		t.Fatal("should have waited")
+	case <-time.After(1 * time.Millisecond):
+	}
+
+	returnArguments := <-ch
+
+	if assert.Equal(t, 1, len(mockedService.Mock.Calls)) {
+		assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments)) {
+		assert.Equal(t, 5, returnArguments[0])
+		assert.Equal(t, "6", returnArguments[1])
+		assert.Equal(t, true, returnArguments[2])
+	}
+
+}
+
+func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(5, "6", true).Once()
+	mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(-1, "hi", false)
+
+	returnArguments1 := mockedService.Called(1, 2, 3)
+	returnArguments2 := mockedService.Called(1, 2, 3)
+
+	if assert.Equal(t, 2, len(mockedService.Calls)) {
+		assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method)
+		assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+
+		assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method)
+		assert.Equal(t, 1, mockedService.Calls[1].Arguments[0])
+		assert.Equal(t, 2, mockedService.Calls[1].Arguments[1])
+		assert.Equal(t, 3, mockedService.Calls[1].Arguments[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments1)) {
+		assert.Equal(t, 5, returnArguments1[0])
+		assert.Equal(t, "6", returnArguments1[1])
+		assert.Equal(t, true, returnArguments1[2])
+	}
+
+	if assert.Equal(t, 3, len(returnArguments2)) {
+		assert.Equal(t, -1, returnArguments2[0])
+		assert.Equal(t, "hi", returnArguments2[1])
+		assert.Equal(t, false, returnArguments2[2])
+	}
+
+}
+
+func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4)
+
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	mockedService.TheExampleMethod(1, 2, 3)
+	assert.Panics(t, func() {
+		mockedService.TheExampleMethod(1, 2, 3)
+	})
+
+}
+
+func Test_Mock_Called_Unexpected(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	// make sure it panics if no expectation was made
+	assert.Panics(t, func() {
+		mockedService.Called(1, 2, 3)
+	}, "Calling unexpected method should panic")
+
+}
+
+func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
+
+	var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return()
+	mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return()
+	mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return()
+
+	mockedService1.Called(1)
+	mockedService2.Called(2)
+	mockedService3.Called(3)
+
+	assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
+
+	var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
+	var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return()
+	mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return()
+	mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return()
+
+	mockedService1.Called(1)
+	mockedService3.Called(3)
+
+	tt := new(testing.T)
+	assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_Mock_AssertExpectations(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7)
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.Called(1, 2, 3)
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once()
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.TheExampleMethod3(&ExampleType{})
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice()
+
+	tt := new(testing.T)
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	// make the call now
+	mockedService.Called(1, 2, 3)
+
+	assert.False(t, mockedService.AssertExpectations(tt))
+
+	mockedService.Called(1, 2, 3)
+
+	// now assert expectations
+	assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7)
+	mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7)
+
+	args1 := mockedService.Called(1, 2, 3)
+	assert.Equal(t, 5, args1.Int(0))
+	assert.Equal(t, 6, args1.Int(1))
+	assert.Equal(t, 7, args1.Int(2))
+
+	args2 := mockedService.Called(4, 5, 6)
+	assert.Equal(t, 5, args2.Int(0))
+	assert.Equal(t, 6, args2.Int(1))
+	assert.Equal(t, 7, args2.Int(2))
+
+}
+
+func Test_Mock_AssertNumberOfCalls(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+	assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1))
+
+	mockedService.Called(1, 2, 3)
+	assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2))
+
+}
+
+func Test_Mock_AssertCalled(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3))
+
+}
+
+func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).Return()
+
+	mockedService.Called(1, "two", []uint8("three"))
+
+	assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8")))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	tt := new(testing.T)
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3))
+	assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once()
+	mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once()
+
+	mockedService.Called(1, 2, 3)
+	mockedService.Called(2, 3, 4)
+
+	tt := new(testing.T)
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3))
+	assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4))
+	assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5))
+
+}
+
+func Test_Mock_AssertNotCalled(t *testing.T) {
+
+	var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+	mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7)
+
+	mockedService.Called(1, 2, 3)
+
+	assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled"))
+
+}
+
+/*
+	Arguments helper methods
+*/
+func Test_Arguments_Get(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.Equal(t, "string", args.Get(0).(string))
+	assert.Equal(t, 123, args.Get(1).(int))
+	assert.Equal(t, true, args.Get(2).(bool))
+
+}
+
+func Test_Arguments_Is(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.True(t, args.Is("string", 123, true))
+	assert.False(t, args.Is("wrong", 456, false))
+
+}
+
+func Test_Arguments_Diff(t *testing.T) {
+
+	var args Arguments = []interface{}{"Hello World", 123, true}
+	var diff string
+	var count int
+	diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
+
+	assert.Equal(t, 2, count)
+	assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`)
+	assert.Contains(t, diff, `false != %!s(bool=true)`)
+
+}
+
+func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	var diff string
+	var count int
+	diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
+
+	assert.Equal(t, 3, count)
+	assert.Contains(t, diff, `extra != (Missing)`)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", Anything, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", Anything, true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", AnythingOfType("int"), true}
+	var count int
+	_, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", AnythingOfType("string"), true}
+	var count int
+	var diff string
+	diff, count = args.Diff([]interface{}{"string", 123, true})
+
+	assert.Equal(t, 1, count)
+	assert.Contains(t, diff, `string != type int - %!s(int=123)`)
+
+}
+
+func Test_Arguments_Assert(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+
+	assert.True(t, args.Assert(t, "string", 123, true))
+
+}
+
+func Test_Arguments_String_Representation(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, `string,int,bool`, args.String())
+
+}
+
+func Test_Arguments_String(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, "string", args.String(0))
+
+}
+
+func Test_Arguments_Error(t *testing.T) {
+
+	var err error = errors.New("An Error")
+	var args Arguments = []interface{}{"string", 123, true, err}
+	assert.Equal(t, err, args.Error(3))
+
+}
+
+func Test_Arguments_Error_Nil(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true, nil}
+	assert.Equal(t, nil, args.Error(3))
+
+}
+
+func Test_Arguments_Int(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, 123, args.Int(1))
+
+}
+
+func Test_Arguments_Bool(t *testing.T) {
+
+	var args Arguments = []interface{}{"string", 123, true}
+	assert.Equal(t, true, args.Bool(2))
+
+}

+ 5 - 0
libnetwork/cmd/dnet/dnet.go

@@ -12,6 +12,7 @@ import (
 
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/reexec"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/term"
@@ -31,6 +32,10 @@ var (
 )
 
 func main() {
+	if reexec.Init() {
+		return
+	}
+
 	_, stdout, stderr := term.StdStreams()
 	logrus.SetOutput(stderr)
 

+ 2 - 2
libnetwork/cmd/test/libnetwork.toml

@@ -3,8 +3,8 @@ title = "LibNetwork Configuration file"
 [daemon]
   debug = false
 [cluster]
-  discovery = "token://ce5b9756aeab50fe8fda02624f093d1c"
-  Address = "1.1.1.1:90"
+  discovery = "token://22aa23948f4f6b31230687689636959e"
+  Address = "1.1.1.1"
 [datastore]
   embedded = false
 [datastore.client]

+ 21 - 5
libnetwork/cmd/test/main.go

@@ -2,16 +2,18 @@ package main
 
 import (
 	"fmt"
-	"log"
 	"net"
 	"os"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
+
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/options"
 )
 
 func main() {
+	log.SetLevel(log.DebugLevel)
 	os.Setenv("LIBNETWORK_CFG", "libnetwork.toml")
 	controller, err := libnetwork.New("libnetwork.toml")
 	if err != nil {
@@ -24,12 +26,26 @@ func main() {
 	options := options.Generic{"AddressIPv4": net}
 
 	err = controller.ConfigureNetworkDriver(netType, options)
-	for i := 0; i < 100; i++ {
+	for i := 0; i < 10; i++ {
 		netw, err := controller.NewNetwork(netType, fmt.Sprintf("Gordon-%d", i))
 		if err != nil {
-			log.Fatal(err)
+			if _, ok := err.(libnetwork.NetworkNameError); !ok {
+				log.Fatal(err)
+			}
+		} else {
+			fmt.Println("Network Created Successfully :", netw)
+		}
+		netw, _ = controller.NetworkByName(fmt.Sprintf("Gordon-%d", i))
+		_, err = netw.CreateEndpoint(fmt.Sprintf("Gordon-Ep-%d", i), nil)
+		if err != nil {
+			log.Fatalf("Error creating endpoint 1 %v", err)
 		}
-		fmt.Println("Network Created Successfully :", netw)
-		time.Sleep(10 * time.Second)
+
+		_, err = netw.CreateEndpoint(fmt.Sprintf("Gordon-Ep2-%d", i), nil)
+		if err != nil {
+			log.Fatalf("Error creating endpoint 2 %v", err)
+		}
+
+		time.Sleep(2 * time.Second)
 	}
 }

+ 59 - 100
libnetwork/controller.go

@@ -45,7 +45,6 @@ create network namespaces and allocate interfaces for containers to use.
 package libnetwork
 
 import (
-	"encoding/json"
 	"fmt"
 	"net"
 	"os"
@@ -61,7 +60,6 @@ import (
 	"github.com/docker/libnetwork/hostdiscovery"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
-	"github.com/docker/swarm/pkg/store"
 )
 
 // NetworkController provides the interface for controller instance which manages
@@ -94,6 +92,12 @@ type NetworkController interface {
 // When the function returns true, the walk will stop.
 type NetworkWalker func(nw Network) bool
 
+type driverData struct {
+	driver     driverapi.Driver
+	capability driverapi.Capability
+}
+
+type driverTable map[string]*driverData
 type networkTable map[types.UUID]*network
 type endpointTable map[types.UUID]*endpoint
 type sandboxTable map[string]*sandboxData
@@ -160,23 +164,6 @@ func (c *controller) initConfig(configFile string) error {
 	return nil
 }
 
-func (c *controller) initDataStore() error {
-	if c.cfg == nil {
-		return fmt.Errorf("datastore initialization requires a valid configuration")
-	}
-
-	store, err := datastore.NewDataStore(&c.cfg.Datastore)
-	if err != nil {
-		return err
-	}
-	c.Lock()
-	c.store = store
-	c.Unlock()
-	go c.watchNewNetworks()
-
-	return nil
-}
-
 func (c *controller) initDiscovery() error {
 	if c.cfg == nil {
 		return fmt.Errorf("discovery initialization requires a valid configuration")
@@ -194,21 +181,21 @@ func (c *controller) hostLeaveCallback(hosts []net.IP) {
 
 func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
 	c.Lock()
-	d, ok := c.drivers[networkType]
+	dd, ok := c.drivers[networkType]
 	c.Unlock()
 	if !ok {
 		return NetworkTypeError(networkType)
 	}
-	return d.Config(options)
+	return dd.driver.Config(options)
 }
 
-func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) error {
+func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
 	c.Lock()
 	defer c.Unlock()
 	if _, ok := c.drivers[networkType]; ok {
 		return driverapi.ErrActiveRegistration(networkType)
 	}
-	c.drivers[networkType] = driver
+	c.drivers[networkType] = &driverData{driver, capability}
 	return nil
 }
 
@@ -218,18 +205,6 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 	if name == "" {
 		return nil, ErrInvalidName(name)
 	}
-	// Check if a driver for the specified network type is available
-	c.Lock()
-	d, ok := c.drivers[networkType]
-	c.Unlock()
-	if !ok {
-		var err error
-		d, err = c.loadDriver(networkType)
-		if err != nil {
-			return nil, err
-		}
-	}
-
 	// Check if a network already exists with the specified network name
 	c.Lock()
 	for _, n := range c.networks {
@@ -242,87 +217,58 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 
 	// Construct the network object
 	network := &network{
-		name:      name,
-		id:        types.UUID(stringid.GenerateRandomID()),
-		ctrlr:     c,
-		driver:    d,
-		endpoints: endpointTable{},
+		name:        name,
+		networkType: networkType,
+		id:          types.UUID(stringid.GenerateRandomID()),
+		ctrlr:       c,
+		endpoints:   endpointTable{},
 	}
 
 	network.processOptions(options...)
-	if err := c.addNetworkToStore(network); err != nil {
+
+	if err := c.addNetwork(network); err != nil {
 		return nil, err
 	}
-	// Create the network
-	if err := d.CreateNetwork(network.id, network.generic); err != nil {
+
+	if err := c.updateNetworkToStore(network); err != nil {
+		if e := network.Delete(); e != nil {
+			log.Warnf("couldnt cleanup network %s: %v", network.name, err)
+		}
 		return nil, err
 	}
 
-	// Store the network handler in controller
-	c.Lock()
-	c.networks[network.id] = network
-	c.Unlock()
-
 	return network, nil
 }
 
-func (c *controller) newNetworkFromStore(n *network) {
-	c.Lock()
-	defer c.Unlock()
-
-	if _, ok := c.drivers[n.networkType]; !ok {
-		log.Warnf("Network driver unavailable for type=%s. ignoring network updates for %s", n.Type(), n.Name())
-		return
-	}
-	n.ctrlr = c
-	n.driver = c.drivers[n.networkType]
-	c.networks[n.id] = n
-	// TODO : Populate n.endpoints back from endpoint dbstore
-}
+func (c *controller) addNetwork(n *network) error {
 
-func (c *controller) addNetworkToStore(n *network) error {
-	if isReservedNetwork(n.Name()) {
-		return nil
-	}
 	c.Lock()
-	cs := c.store
+	// Check if a driver for the specified network type is available
+	dd, ok := c.drivers[n.networkType]
 	c.Unlock()
-	if cs == nil {
-		log.Debugf("datastore not initialized. Network %s is not added to the store", n.Name())
-		return nil
+
+	if !ok {
+		var err error
+		dd, err = c.loadDriver(n.networkType)
+		if err != nil {
+			return err
+		}
 	}
-	return cs.PutObjectAtomic(n)
-}
 
-func (c *controller) watchNewNetworks() {
+	n.Lock()
+	n.driver = dd.driver
+	d := n.driver
+	n.Unlock()
+
+	// Create the network
+	if err := d.CreateNetwork(n.id, n.generic); err != nil {
+		return err
+	}
 	c.Lock()
-	cs := c.store
+	c.networks[n.id] = n
 	c.Unlock()
 
-	cs.KVStore().WatchRange(datastore.Key(datastore.NetworkKeyPrefix), "", 0, func(kvi []store.KVEntry) {
-		for _, kve := range kvi {
-			var n network
-			err := json.Unmarshal(kve.Value(), &n)
-			if err != nil {
-				log.Error(err)
-				continue
-			}
-			n.dbIndex = kve.LastIndex()
-			c.Lock()
-			existing, ok := c.networks[n.id]
-			c.Unlock()
-			if ok && existing.dbIndex == n.dbIndex {
-				// Skip any watch notification for a network that has not changed
-				continue
-			} else if ok {
-				// Received an update for an existing network object
-				log.Debugf("Skipping network update for %s (%s)", n.name, n.id)
-				continue
-			}
-
-			c.newNetworkFromStore(&n)
-		}
-	})
+	return nil
 }
 
 func (c *controller) Networks() []Network {
@@ -380,7 +326,7 @@ func (c *controller) NetworkByID(id string) (Network, error) {
 	return nil, ErrNoSuchNetwork(id)
 }
 
-func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
+func (c *controller) loadDriver(networkType string) (*driverData, error) {
 	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
@@ -392,11 +338,24 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
 	}
 	c.Lock()
 	defer c.Unlock()
-	d, ok := c.drivers[networkType]
+	dd, ok := c.drivers[networkType]
 	if !ok {
 		return nil, ErrInvalidNetworkDriver(networkType)
 	}
-	return d, nil
+	return dd, nil
+}
+
+func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
+	c.Lock()
+	dd, ok := c.drivers[networkType]
+	c.Unlock()
+	if !ok {
+		return false, types.NotFoundErrorf("driver not found for %s", networkType)
+	}
+	if dd.capability.Scope == driverapi.GlobalScope {
+		return true, nil
+	}
+	return false, nil
 }
 
 func (c *controller) GC() {

+ 69 - 19
libnetwork/datastore/datastore.go

@@ -1,19 +1,29 @@
 package datastore
 
 import (
-	"errors"
+	"encoding/json"
+	"reflect"
 	"strings"
 
 	"github.com/docker/libnetwork/config"
+	"github.com/docker/libnetwork/types"
 	"github.com/docker/swarm/pkg/store"
 )
 
 //DataStore exported
 type DataStore interface {
+	// GetObject gets data from datastore and unmarshals to the specified object
+	GetObject(key string, o interface{}) error
 	// PutObject adds a new Record based on an object into the datastore
 	PutObject(kvObject KV) error
 	// PutObjectAtomic provides an atomic add and update operation for a Record
 	PutObjectAtomic(kvObject KV) error
+	// DeleteObject deletes a record
+	DeleteObject(kvObject KV) error
+	// DeleteObjectAtomic performs an atomic delete operation
+	DeleteObjectAtomic(kvObject KV) error
+	// DeleteTree deletes a record
+	DeleteTree(kvObject KV) error
 	// KVStore returns access to the KV Store
 	KVStore() store.Store
 }
@@ -26,6 +36,8 @@ type datastore struct {
 type KV interface {
 	// Key method lets an object to provide the Key to be used in KV Store
 	Key() []string
+	// KeyPrefix method lets an object to return immediate parent key that can be used for tree walk
+	KeyPrefix() []string
 	// Value method lets an object to marshal its content to be stored in the KV store
 	Value() []byte
 	// Index method returns the latest DB Index as seen by the object
@@ -37,23 +49,33 @@ type KV interface {
 const (
 	// NetworkKeyPrefix is the prefix for network key in the kv store
 	NetworkKeyPrefix = "network"
+	// EndpointKeyPrefix is the prefix for endpoint key in the kv store
+	EndpointKeyPrefix = "endpoint"
 )
 
+var rootChain = []string{"docker", "libnetwork"}
+
 //Key provides convenient method to create a Key
 func Key(key ...string) string {
-	keychain := []string{"docker", "libnetwork"}
-	keychain = append(keychain, key...)
+	keychain := append(rootChain, key...)
 	str := strings.Join(keychain, "/")
 	return str + "/"
 }
 
-var errNewDatastore = errors.New("Error creating new Datastore")
-var errInvalidConfiguration = errors.New("Invalid Configuration passed to Datastore")
-var errInvalidAtomicRequest = errors.New("Invalid Atomic Request")
+//ParseKey provides convenient method to unpack the key to complement the Key function
+func ParseKey(key string) ([]string, error) {
+	chain := strings.Split(strings.Trim(key, "/"), "/")
+
+	// The key must atleast be equal to the rootChain in order to be considered as valid
+	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
+		return nil, types.BadRequestErrorf("invalid Key : %s", key)
+	}
+	return chain[len(rootChain):], nil
+}
 
 // newClient used to connect to KV Store
 func newClient(kv string, addrs string) (DataStore, error) {
-	store, err := store.CreateStore(kv, []string{addrs}, store.Config{})
+	store, err := store.NewStore(store.Backend(kv), []string{addrs}, &store.Config{})
 	if err != nil {
 		return nil, err
 	}
@@ -64,7 +86,7 @@ func newClient(kv string, addrs string) (DataStore, error) {
 // NewDataStore creates a new instance of LibKV data store
 func NewDataStore(cfg *config.DatastoreCfg) (DataStore, error) {
 	if cfg == nil {
-		return nil, errInvalidConfiguration
+		return nil, types.BadRequestErrorf("invalid configuration passed to datastore")
 	}
 	// TODO : cfg.Embedded case
 	return newClient(cfg.Client.Provider, cfg.Client.Address)
@@ -82,30 +104,28 @@ func (ds *datastore) KVStore() store.Store {
 // PutObjectAtomic adds a new Record based on an object into the datastore
 func (ds *datastore) PutObjectAtomic(kvObject KV) error {
 	if kvObject == nil {
-		return errors.New("kvObject is nil")
+		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
 	kvObjValue := kvObject.Value()
 
 	if kvObjValue == nil {
-		return errInvalidAtomicRequest
-	}
-	_, err := ds.store.AtomicPut(Key(kvObject.Key()...), []byte{}, kvObjValue, kvObject.Index())
-	if err != nil {
-		return err
+		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
 	}
 
-	_, index, err := ds.store.Get(Key(kvObject.Key()...))
+	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
+	_, pair, err := ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
 	if err != nil {
 		return err
 	}
-	kvObject.SetIndex(index)
+
+	kvObject.SetIndex(pair.LastIndex)
 	return nil
 }
 
 // PutObject adds a new Record based on an object into the datastore
 func (ds *datastore) PutObject(kvObject KV) error {
 	if kvObject == nil {
-		return errors.New("kvObject is nil")
+		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
 	return ds.putObjectWithKey(kvObject, kvObject.Key()...)
 }
@@ -114,7 +134,37 @@ func (ds *datastore) putObjectWithKey(kvObject KV, key ...string) error {
 	kvObjValue := kvObject.Value()
 
 	if kvObjValue == nil {
-		return errors.New("Object must provide marshalled data for key : " + Key(kvObject.Key()...))
+		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
+	}
+	return ds.store.Put(Key(key...), kvObjValue, nil)
+}
+
+// GetObject returns a record matching the key
+func (ds *datastore) GetObject(key string, o interface{}) error {
+	kvPair, err := ds.store.Get(key)
+	if err != nil {
+		return err
 	}
-	return ds.store.Put(Key(key...), kvObjValue)
+	return json.Unmarshal(kvPair.Value, o)
+}
+
+// DeleteObject unconditionally deletes a record from the store
+func (ds *datastore) DeleteObject(kvObject KV) error {
+	return ds.store.Delete(Key(kvObject.Key()...))
+}
+
+// DeleteObjectAtomic performs atomic delete on a record
+func (ds *datastore) DeleteObjectAtomic(kvObject KV) error {
+	if kvObject == nil {
+		return types.BadRequestErrorf("invalid KV Object : nil")
+	}
+
+	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
+	_, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous)
+	return err
+}
+
+// DeleteTree unconditionally deletes a record from the store
+func (ds *datastore) DeleteTree(kvObject KV) error {
+	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
 }

+ 30 - 5
libnetwork/datastore/datastore_test.go

@@ -2,6 +2,7 @@ package datastore
 
 import (
 	"encoding/json"
+	"reflect"
 	"testing"
 
 	"github.com/docker/libnetwork/config"
@@ -16,6 +17,25 @@ func NewTestDataStore() DataStore {
 	return &datastore{store: NewMockStore()}
 }
 
+func TestKey(t *testing.T) {
+	eKey := []string{"hello", "world"}
+	sKey := Key(eKey...)
+	if sKey != "docker/libnetwork/hello/world/" {
+		t.Fatalf("unexpected key : %s", sKey)
+	}
+}
+
+func TestParseKey(t *testing.T) {
+	keySlice, err := ParseKey("/docker/libnetwork/hello/world/")
+	if err != nil {
+		t.Fatal(err)
+	}
+	eKey := []string{"hello", "world"}
+	if len(keySlice) < 2 || !reflect.DeepEqual(eKey, keySlice) {
+		t.Fatalf("unexpected unkey : %s", keySlice)
+	}
+}
+
 func TestInvalidDataStore(t *testing.T) {
 	config := &config.DatastoreCfg{}
 	config.Embedded = false
@@ -35,12 +55,12 @@ func TestKVObjectFlatKey(t *testing.T) {
 		t.Fatal(err)
 	}
 	keychain := []string{dummyKey, "1000"}
-	data, _, err := store.KVStore().Get(Key(keychain...))
+	data, err := store.KVStore().Get(Key(keychain...))
 	if err != nil {
 		t.Fatal(err)
 	}
 	var n dummyObject
-	json.Unmarshal(data, &n)
+	json.Unmarshal(data.Value, &n)
 	if n.Name != expected.Name {
 		t.Fatalf("Dummy object doesnt match the expected object")
 	}
@@ -63,14 +83,14 @@ func TestAtomicKVObjectFlatKey(t *testing.T) {
 
 	// Get the latest index and try PutObjectAtomic again for the same Key
 	// This must succeed as well
-	data, index, err := store.KVStore().Get(Key(expected.Key()...))
+	data, err := store.KVStore().Get(Key(expected.Key()...))
 	if err != nil {
 		t.Fatal(err)
 	}
 	n := dummyObject{}
-	json.Unmarshal(data, &n)
+	json.Unmarshal(data.Value, &n)
 	n.ID = "1111"
-	n.DBIndex = index
+	n.DBIndex = data.LastIndex
 	n.ReturnValue = true
 	err = store.PutObjectAtomic(&n)
 	if err != nil {
@@ -94,6 +114,11 @@ type dummyObject struct {
 func (n *dummyObject) Key() []string {
 	return []string{dummyKey, n.ID}
 }
+
+func (n *dummyObject) KeyPrefix() []string {
+	return []string{dummyKey}
+}
+
 func (n *dummyObject) Value() []byte {
 	if !n.ReturnValue {
 		return nil

+ 35 - 47
libnetwork/datastore/mock_store.go

@@ -2,8 +2,8 @@ package datastore
 
 import (
 	"errors"
-	"time"
 
+	"github.com/docker/libnetwork/types"
 	"github.com/docker/swarm/pkg/store"
 )
 
@@ -31,17 +31,17 @@ func NewMockStore() *MockStore {
 
 // Get the value at "key", returns the last modified index
 // to use in conjunction to CAS calls
-func (s *MockStore) Get(key string) (value []byte, lastIndex uint64, err error) {
+func (s *MockStore) Get(key string) (*store.KVPair, error) {
 	mData := s.db[key]
 	if mData == nil {
-		return nil, 0, nil
+		return nil, nil
 	}
-	return mData.Data, mData.Index, nil
+	return &store.KVPair{Value: mData.Data, LastIndex: mData.Index}, nil
 
 }
 
 // Put a value at "key"
-func (s *MockStore) Put(key string, value []byte) error {
+func (s *MockStore) Put(key string, value []byte, options *store.WriteOptions) error {
 	mData := s.db[key]
 	if mData == nil {
 		mData = &MockData{value, 0}
@@ -63,69 +63,57 @@ func (s *MockStore) Exists(key string) (bool, error) {
 	return ok, nil
 }
 
-// GetRange gets a range of values at "directory"
-func (s *MockStore) GetRange(prefix string) (values []store.KVEntry, err error) {
+// List gets a range of values at "directory"
+func (s *MockStore) List(prefix string) ([]*store.KVPair, error) {
 	return nil, ErrNotImplmented
 }
 
-// DeleteRange deletes a range of values at "directory"
-func (s *MockStore) DeleteRange(prefix string) error {
-	return ErrNotImplmented
-}
-
-// Watch a single key for modifications
-func (s *MockStore) Watch(key string, heartbeat time.Duration, callback store.WatchCallback) error {
-	return ErrNotImplmented
-}
-
-// CancelWatch cancels a watch, sends a signal to the appropriate
-// stop channel
-func (s *MockStore) CancelWatch(key string) error {
-	return ErrNotImplmented
-}
-
-// Internal function to check if a key has changed
-func (s *MockStore) waitForChange(key string) <-chan uint64 {
+// DeleteTree deletes a range of values at "directory"
+func (s *MockStore) DeleteTree(prefix string) error {
+	delete(s.db, prefix)
 	return nil
 }
 
-// WatchRange triggers a watch on a range of values at "directory"
-func (s *MockStore) WatchRange(prefix string, filter string, heartbeat time.Duration, callback store.WatchCallback) error {
-	return ErrNotImplmented
-}
-
-// CancelWatchRange stops the watch on the range of values, sends
-// a signal to the appropriate stop channel
-func (s *MockStore) CancelWatchRange(prefix string) error {
-	return ErrNotImplmented
+// Watch a single key for modifications
+func (s *MockStore) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
+	return nil, ErrNotImplmented
 }
 
-// Acquire the lock for "key"/"directory"
-func (s *MockStore) Acquire(key string, value []byte) (string, error) {
-	return "", ErrNotImplmented
+// WatchTree triggers a watch on a range of values at "directory"
+func (s *MockStore) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
+	return nil, ErrNotImplmented
 }
 
-// Release the lock for "key"/"directory"
-func (s *MockStore) Release(id string) error {
-	return ErrNotImplmented
+// NewLock exposed
+func (s *MockStore) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
+	return nil, ErrNotImplmented
 }
 
 // AtomicPut put a value at "key" if the key has not been
 // modified in the meantime, throws an error if this is the case
-func (s *MockStore) AtomicPut(key string, _ []byte, newValue []byte, index uint64) (bool, error) {
+func (s *MockStore) AtomicPut(key string, newValue []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
 	mData := s.db[key]
-	if mData != nil && mData.Index != index {
-		return false, errInvalidAtomicRequest
+	if mData != nil && mData.Index != previous.LastIndex {
+		return false, nil, types.BadRequestErrorf("atomic put failed due to mismatched Index")
+	}
+	err := s.Put(key, newValue, nil)
+	if err != nil {
+		return false, nil, err
 	}
-	return true, s.Put(key, newValue)
+	return true, &store.KVPair{Key: key, Value: newValue, LastIndex: s.db[key].Index}, nil
 }
 
 // AtomicDelete deletes a value at "key" if the key has not
 // been modified in the meantime, throws an error if this is the case
-func (s *MockStore) AtomicDelete(key string, oldValue []byte, index uint64) (bool, error) {
+func (s *MockStore) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
 	mData := s.db[key]
-	if mData != nil && mData.Index != index {
-		return false, errInvalidAtomicRequest
+	if mData != nil && mData.Index != previous.LastIndex {
+		return false, types.BadRequestErrorf("atomic delete failed due to mismatched Index")
 	}
 	return true, s.Delete(key)
 }
+
+// Close closes the client connection
+func (s *MockStore) Close() {
+	return
+}

+ 16 - 1
libnetwork/driverapi/driverapi.go

@@ -118,5 +118,20 @@ type JoinInfo interface {
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 type DriverCallback interface {
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
-	RegisterDriver(name string, driver Driver) error
+	RegisterDriver(name string, driver Driver, capability Capability) error
+}
+
+// Scope indicates the drivers scope capability
+type Scope int
+
+const (
+	// LocalScope represents the driver capable of providing networking services for containers in a single host
+	LocalScope Scope = iota
+	// GlobalScope represents the driver capable of providing networking services for containers across hosts
+	GlobalScope
+)
+
+// Capability represents the high level capabilities of the drivers which libnetwork can make use of
+type Capability struct {
+	Scope Scope
 }

+ 4 - 2
libnetwork/drivers/bridge/bridge.go

@@ -110,8 +110,10 @@ func Init(dc driverapi.DriverCallback) error {
 	if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
 		logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
 	}
-
-	return dc.RegisterDriver(networkType, newDriver())
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, newDriver(), c)
 }
 
 // Validate performs a static validation on the network configuration parameters.

+ 4 - 1
libnetwork/drivers/host/host.go

@@ -16,7 +16,10 @@ type driver struct {
 
 // Init registers a new instance of host driver
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
 func (d *driver) Config(option map[string]interface{}) error {

+ 4 - 1
libnetwork/drivers/null/null.go

@@ -16,7 +16,10 @@ type driver struct {
 
 // Init registers a new instance of null driver
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
 func (d *driver) Config(option map[string]interface{}) error {

+ 4 - 1
libnetwork/drivers/remote/driver.go

@@ -23,7 +23,10 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver {
 // plugin is activated.
 func Init(dc driverapi.DriverCallback) error {
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
-		if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil {
+		c := driverapi.Capability{
+			Scope: driverapi.GlobalScope,
+		}
+		if err := dc.RegisterDriver(name, newDriver(name, client), c); err != nil {
 			log.Errorf("error registering driver for %s due to %v", name, err)
 		}
 	})

+ 4 - 1
libnetwork/drivers/windows/windows.go

@@ -13,7 +13,10 @@ type driver struct{}
 
 // Init registers a new instance of null driver
 func Init(dc driverapi.DriverCallback) error {
-	return dc.RegisterDriver(networkType, &driver{})
+	c := driverapi.Capability{
+		Scope: driverapi.LocalScope,
+	}
+	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
 func (d *driver) Config(option map[string]interface{}) error {

+ 0 - 2
libnetwork/drivers_freebsd.go

@@ -6,8 +6,6 @@ import (
 	"github.com/docker/libnetwork/drivers/remote"
 )
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		null.Init,

+ 0 - 2
libnetwork/drivers_linux.go

@@ -8,8 +8,6 @@ import (
 	"github.com/docker/libnetwork/drivers/remote"
 )
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		bridge.Init,

+ 0 - 2
libnetwork/drivers_windows.go

@@ -5,8 +5,6 @@ import (
 	"github.com/docker/libnetwork/drivers/windows"
 )
 
-type driverTable map[string]driverapi.Driver
-
 func initDrivers(dc driverapi.DriverCallback) error {
 	for _, fn := range [](func(driverapi.DriverCallback) error){
 		windows.Init,

+ 190 - 5
libnetwork/endpoint.go

@@ -2,6 +2,8 @@ package libnetwork
 
 import (
 	"bytes"
+	"encoding/json"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path"
@@ -10,6 +12,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/resolvconf"
@@ -96,6 +99,7 @@ type containerInfo struct {
 	id     string
 	config containerConfig
 	data   ContainerData
+	sync.Mutex
 }
 
 type endpoint struct {
@@ -108,9 +112,84 @@ type endpoint struct {
 	exposedPorts  []types.TransportPort
 	generic       map[string]interface{}
 	joinLeaveDone chan struct{}
+	dbIndex       uint64
 	sync.Mutex
 }
 
+func (ci *containerInfo) MarshalJSON() ([]byte, error) {
+	ci.Lock()
+	defer ci.Unlock()
+
+	// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
+	return json.Marshal(ci.id)
+}
+
+func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
+	ci.Lock()
+	defer ci.Unlock()
+
+	var id string
+	if err := json.Unmarshal(b, &id); err != nil {
+		return err
+	}
+	ci.id = id
+	return nil
+}
+
+func (ep *endpoint) MarshalJSON() ([]byte, error) {
+	ep.Lock()
+	defer ep.Unlock()
+
+	epMap := make(map[string]interface{})
+	epMap["name"] = ep.name
+	epMap["id"] = string(ep.id)
+	epMap["ep_iface"] = ep.iFaces
+	epMap["exposed_ports"] = ep.exposedPorts
+	epMap["generic"] = ep.generic
+	if ep.container != nil {
+		epMap["container"] = ep.container
+	}
+	return json.Marshal(epMap)
+}
+
+func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
+	ep.Lock()
+	defer ep.Unlock()
+
+	var epMap map[string]interface{}
+	if err := json.Unmarshal(b, &epMap); err != nil {
+		return err
+	}
+	ep.name = epMap["name"].(string)
+	ep.id = types.UUID(epMap["id"].(string))
+
+	ib, _ := json.Marshal(epMap["ep_iface"])
+	var ifaces []endpointInterface
+	json.Unmarshal(ib, &ifaces)
+	ep.iFaces = make([]*endpointInterface, 0)
+	for _, iface := range ifaces {
+		ep.iFaces = append(ep.iFaces, &iface)
+	}
+
+	tb, _ := json.Marshal(epMap["exposed_ports"])
+	var tPorts []types.TransportPort
+	json.Unmarshal(tb, &tPorts)
+	ep.exposedPorts = tPorts
+
+	epc, ok := epMap["container"]
+	if ok {
+		cb, _ := json.Marshal(epc)
+		var cInfo containerInfo
+		json.Unmarshal(cb, &cInfo)
+		ep.container = &cInfo
+	}
+
+	if epMap["generic"] != nil {
+		ep.generic = epMap["generic"].(map[string]interface{})
+	}
+	return nil
+}
+
 const defaultPrefix = "/var/lib/docker/network/files"
 
 func (ep *endpoint) ID() string {
@@ -134,6 +213,52 @@ func (ep *endpoint) Network() string {
 	return ep.network.name
 }
 
+// endpoint Key structure : endpoint/network-id/endpoint-id
+func (ep *endpoint) Key() []string {
+	ep.Lock()
+	n := ep.network
+	defer ep.Unlock()
+	return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
+}
+
+func (ep *endpoint) KeyPrefix() []string {
+	ep.Lock()
+	n := ep.network
+	defer ep.Unlock()
+	return []string{datastore.EndpointKeyPrefix, string(n.id)}
+}
+
+func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
+	// endpoint Key structure : endpoint/network-id/endpoint-id
+	// its an invalid key if the key doesnt have all the 3 key elements above
+	if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
+		return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
+	}
+
+	// network-id is placed at index=1. pls refer to endpoint.Key() method
+	return types.UUID(key[1]), nil
+}
+
+func (ep *endpoint) Value() []byte {
+	b, err := json.Marshal(ep)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+func (ep *endpoint) Index() uint64 {
+	ep.Lock()
+	defer ep.Unlock()
+	return ep.dbIndex
+}
+
+func (ep *endpoint) SetIndex(index uint64) {
+	ep.Lock()
+	defer ep.Unlock()
+	ep.dbIndex = index
+}
+
 func (ep *endpoint) processOptions(options ...EndpointOption) {
 	ep.Lock()
 	defer ep.Unlock()
@@ -211,7 +336,14 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 	}
 
 	ep.joinLeaveStart()
-	defer ep.joinLeaveEnd()
+	defer func() {
+		ep.joinLeaveEnd()
+		if err != nil {
+			if e := ep.Leave(containerID, options...); e != nil {
+				log.Warnf("couldnt leave endpoint : %v", ep.name, err)
+			}
+		}
+	}()
 
 	ep.Lock()
 	if ep.container != nil {
@@ -236,11 +368,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 
 	ep.Unlock()
 	defer func() {
-		ep.Lock()
 		if err != nil {
+			ep.Lock()
 			ep.container = nil
+			ep.Unlock()
 		}
-		ep.Unlock()
 	}()
 
 	network.Lock()
@@ -286,8 +418,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 		}
 	}()
 
-	container.data.SandboxKey = sb.Key()
+	if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
+		return err
+	}
 
+	container.data.SandboxKey = sb.Key()
 	return nil
 }
 
@@ -316,7 +451,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	container := ep.container
 	n := ep.network
 
-	if container == nil || container.id == "" ||
+	if container == nil || container.id == "" || container.data.SandboxKey == "" ||
 		containerID == "" || container.id != containerID {
 		if container == nil {
 			err = ErrNoContainer{}
@@ -335,6 +470,13 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	ctrlr := n.ctrlr
 	n.Unlock()
 
+	if err := ctrlr.updateEndpointToStore(ep); err != nil {
+		ep.Lock()
+		ep.container = container
+		ep.Unlock()
+		return err
+	}
+
 	err = driver.Leave(n.id, ep.id)
 
 	ctrlr.sandboxRm(container.data.SandboxKey, ep)
@@ -343,15 +485,58 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 }
 
 func (ep *endpoint) Delete() error {
+	var err error
 	ep.Lock()
 	epid := ep.id
 	name := ep.name
+	n := ep.network
 	if ep.container != nil {
 		ep.Unlock()
 		return &ActiveContainerError{name: name, id: string(epid)}
 	}
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+	ep.Unlock()
+
+	if err = ctrlr.deleteEndpointFromStore(ep); err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			ep.SetIndex(0)
+			if e := ctrlr.updateEndpointToStore(ep); e != nil {
+				log.Warnf("failed to recreate endpoint in store %s : %v", name, err)
+			}
+		}
+	}()
+
+	// Update the endpoint count in network and update it in the datastore
+	n.DecEndpointCnt()
+	if err = ctrlr.updateNetworkToStore(n); err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			n.IncEndpointCnt()
+			if e := ctrlr.updateNetworkToStore(n); e != nil {
+				log.Warnf("failed to update network %s : %v", n.name, e)
+			}
+		}
+	}()
+
+	if err = ep.deleteEndpoint(); err != nil {
+		return err
+	}
 
+	return nil
+}
+
+func (ep *endpoint) deleteEndpoint() error {
+	ep.Lock()
 	n := ep.network
+	name := ep.name
+	epid := ep.id
 	ep.Unlock()
 
 	n.Lock()

+ 65 - 11
libnetwork/endpoint_info.go

@@ -1,6 +1,7 @@
 package libnetwork
 
 import (
+	"encoding/json"
 	"net"
 
 	"github.com/docker/libnetwork/driverapi"
@@ -49,6 +50,59 @@ type endpointInterface struct {
 	routes    []*net.IPNet
 }
 
+func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
+	epMap := make(map[string]interface{})
+	epMap["id"] = epi.id
+	epMap["mac"] = epi.mac.String()
+	epMap["addr"] = epi.addr.String()
+	epMap["addrv6"] = epi.addrv6.String()
+	epMap["srcName"] = epi.srcName
+	epMap["dstPrefix"] = epi.dstPrefix
+	var routes []string
+	for _, route := range epi.routes {
+		routes = append(routes, route.String())
+	}
+	epMap["routes"] = routes
+	return json.Marshal(epMap)
+}
+
+func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
+	var epMap map[string]interface{}
+	if err := json.Unmarshal(b, &epMap); err != nil {
+		return err
+	}
+	epi.id = int(epMap["id"].(float64))
+
+	mac, _ := net.ParseMAC(epMap["mac"].(string))
+	epi.mac = mac
+
+	_, ipnet, _ := net.ParseCIDR(epMap["addr"].(string))
+	if ipnet != nil {
+		epi.addr = *ipnet
+	}
+
+	_, ipnet, _ = net.ParseCIDR(epMap["addrv6"].(string))
+	if ipnet != nil {
+		epi.addrv6 = *ipnet
+	}
+
+	epi.srcName = epMap["srcName"].(string)
+	epi.dstPrefix = epMap["dstPrefix"].(string)
+
+	rb, _ := json.Marshal(epMap["routes"])
+	var routes []string
+	json.Unmarshal(rb, &routes)
+	epi.routes = make([]*net.IPNet, 0)
+	for _, route := range routes {
+		_, ipr, err := net.ParseCIDR(route)
+		if err == nil {
+			epi.routes = append(epi.routes, ipr)
+		}
+	}
+
+	return nil
+}
+
 type endpointJoinInfo struct {
 	gw             net.IP
 	gw6            net.IP
@@ -116,25 +170,25 @@ func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, i
 	return nil
 }
 
-func (i *endpointInterface) ID() int {
-	return i.id
+func (epi *endpointInterface) ID() int {
+	return epi.id
 }
 
-func (i *endpointInterface) MacAddress() net.HardwareAddr {
-	return types.GetMacCopy(i.mac)
+func (epi *endpointInterface) MacAddress() net.HardwareAddr {
+	return types.GetMacCopy(epi.mac)
 }
 
-func (i *endpointInterface) Address() net.IPNet {
-	return (*types.GetIPNetCopy(&i.addr))
+func (epi *endpointInterface) Address() net.IPNet {
+	return (*types.GetIPNetCopy(&epi.addr))
 }
 
-func (i *endpointInterface) AddressIPv6() net.IPNet {
-	return (*types.GetIPNetCopy(&i.addrv6))
+func (epi *endpointInterface) AddressIPv6() net.IPNet {
+	return (*types.GetIPNetCopy(&epi.addrv6))
 }
 
-func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error {
-	i.srcName = srcName
-	i.dstPrefix = dstPrefix
+func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
+	epi.srcName = srcName
+	epi.dstPrefix = dstPrefix
 	return nil
 }
 

+ 29 - 25
libnetwork/hostdiscovery/hostdiscovery.go

@@ -24,7 +24,8 @@ import (
 	_ "github.com/docker/swarm/discovery/token"
 )
 
-const defaultHeartbeat = 10
+const defaultHeartbeat = time.Duration(10) * time.Second
+const TTLFactor = 3
 
 type hostDiscovery struct {
 	discovery discovery.Discovery
@@ -43,17 +44,17 @@ func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback Join
 		return fmt.Errorf("discovery requires a valid configuration")
 	}
 
-	hb := cfg.Heartbeat
+	hb := time.Duration(cfg.Heartbeat) * time.Second
 	if hb == 0 {
 		hb = defaultHeartbeat
 	}
-	d, err := discovery.New(cfg.Discovery, hb)
+	d, err := discovery.New(cfg.Discovery, hb, TTLFactor*hb)
 	if err != nil {
 		return err
 	}
 
 	if ip := net.ParseIP(cfg.Address); ip == nil {
-		return errors.New("Address config should be either ipv4 or ipv6 address")
+		return errors.New("address config should be either ipv4 or ipv6 address")
 	}
 
 	if err := d.Register(cfg.Address + ":0"); err != nil {
@@ -64,14 +65,25 @@ func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback Join
 	h.discovery = d
 	h.Unlock()
 
-	go d.Watch(func(entries []*discovery.Entry) {
-		h.processCallback(entries, joinCallback, leaveCallback)
-	})
-
-	go sustainHeartbeat(d, hb, cfg, h.stopChan)
+	discoveryCh, errCh := d.Watch(h.stopChan)
+	go h.monitorDiscovery(discoveryCh, errCh, joinCallback, leaveCallback)
+	go h.sustainHeartbeat(d, hb, cfg)
 	return nil
 }
 
+func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-chan error, joinCallback JoinCallback, leaveCallback LeaveCallback) {
+	for {
+		select {
+		case entries := <-ch:
+			h.processCallback(entries, joinCallback, leaveCallback)
+		case err := <-errCh:
+			log.Errorf("discovery error: %v", err)
+		case <-h.stopChan:
+			return
+		}
+	}
+}
+
 func (h *hostDiscovery) StopDiscovery() error {
 	h.Lock()
 	stopChan := h.stopChan
@@ -82,12 +94,12 @@ func (h *hostDiscovery) StopDiscovery() error {
 	return nil
 }
 
-func sustainHeartbeat(d discovery.Discovery, hb uint64, config *config.ClusterCfg, stopChan chan struct{}) {
+func (h *hostDiscovery) sustainHeartbeat(d discovery.Discovery, hb time.Duration, config *config.ClusterCfg) {
 	for {
 		select {
-		case <-stopChan:
+		case <-h.stopChan:
 			return
-		case <-time.After(time.Duration(hb) * time.Second):
+		case <-time.After(hb):
 			if err := d.Register(config.Address + ":0"); err != nil {
 				log.Warn(err)
 			}
@@ -95,7 +107,7 @@ func sustainHeartbeat(d discovery.Discovery, hb uint64, config *config.ClusterCf
 	}
 }
 
-func (h *hostDiscovery) processCallback(entries []*discovery.Entry, joinCallback JoinCallback, leaveCallback LeaveCallback) {
+func (h *hostDiscovery) processCallback(entries discovery.Entries, joinCallback JoinCallback, leaveCallback LeaveCallback) {
 	updated := hosts(entries)
 	h.Lock()
 	existing := h.nodes
@@ -125,23 +137,15 @@ func diff(existing mapset.Set, updated mapset.Set) (added []net.IP, removed []ne
 
 func (h *hostDiscovery) Fetch() ([]net.IP, error) {
 	h.Lock()
-	hd := h.discovery
-	h.Unlock()
-	if hd == nil {
-		return nil, errors.New("No Active Discovery")
-	}
-	entries, err := hd.Fetch()
-	if err != nil {
-		return nil, err
-	}
+	defer h.Unlock()
 	ips := []net.IP{}
-	for _, entry := range entries {
-		ips = append(ips, net.ParseIP(entry.Host))
+	for _, ipstr := range h.nodes.ToSlice() {
+		ips = append(ips, net.ParseIP(ipstr.(string)))
 	}
 	return ips, nil
 }
 
-func hosts(entries []*discovery.Entry) mapset.Set {
+func hosts(entries discovery.Entries) mapset.Set {
 	hosts := mapset.NewSet()
 	for _, entry := range entries {
 		hosts.Add(entry.Host)

+ 2 - 2
libnetwork/hostdiscovery/hostdiscovery_test.go

@@ -15,7 +15,7 @@ import (
 )
 
 func TestDiscovery(t *testing.T) {
-	_, err := net.Dial("tcp", "discovery-stage.hub.docker.com:80")
+	_, err := net.DialTimeout("tcp", "discovery-stage.hub.docker.com:80", 10*time.Second)
 	if err != nil {
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 	}
@@ -52,7 +52,7 @@ func TestDiscovery(t *testing.T) {
 }
 
 func TestBadDiscovery(t *testing.T) {
-	_, err := net.Dial("tcp", "discovery-stage.hub.docker.com:80")
+	_, err := net.DialTimeout("tcp", "discovery-stage.hub.docker.com:80", 10*time.Second)
 	if err != nil {
 		t.Skip("Skipping Discovery test which need connectivity to discovery-stage.hub.docker.com")
 	}

+ 2 - 2
libnetwork/libnetwork_internal_test.go

@@ -13,14 +13,14 @@ func TestDriverRegistration(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = c.(*controller).RegisterDriver(bridgeNetType, nil)
+	err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{})
 	if err == nil {
 		t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
 	}
 	if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
-	err = c.(*controller).RegisterDriver("test-dummy", nil)
+	err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{})
 	if err != nil {
 		t.Fatalf("Test failed with an error %v", err)
 	}

+ 127 - 25
libnetwork/network.go

@@ -2,7 +2,6 @@ package libnetwork
 
 import (
 	"encoding/json"
-	"strings"
 	"sync"
 
 	log "github.com/Sirupsen/logrus"
@@ -12,6 +11,7 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
+	"github.com/docker/swarm/pkg/store"
 )
 
 // A Network represents a logical connectivity zone that containers may
@@ -58,6 +58,7 @@ type network struct {
 	id          types.UUID
 	driver      driverapi.Driver
 	enableIPv6  bool
+	endpointCnt uint64
 	endpoints   endpointTable
 	generic     options.Generic
 	dbIndex     uint64
@@ -90,10 +91,18 @@ func (n *network) Type() string {
 }
 
 func (n *network) Key() []string {
+	n.Lock()
+	defer n.Unlock()
 	return []string{datastore.NetworkKeyPrefix, string(n.id)}
 }
 
+func (n *network) KeyPrefix() []string {
+	return []string{datastore.NetworkKeyPrefix}
+}
+
 func (n *network) Value() []byte {
+	n.Lock()
+	defer n.Unlock()
 	b, err := json.Marshal(n)
 	if err != nil {
 		return nil
@@ -102,11 +111,33 @@ func (n *network) Value() []byte {
 }
 
 func (n *network) Index() uint64 {
+	n.Lock()
+	defer n.Unlock()
 	return n.dbIndex
 }
 
 func (n *network) SetIndex(index uint64) {
+	n.Lock()
 	n.dbIndex = index
+	n.Unlock()
+}
+
+func (n *network) EndpointCnt() uint64 {
+	n.Lock()
+	defer n.Unlock()
+	return n.endpointCnt
+}
+
+func (n *network) IncEndpointCnt() {
+	n.Lock()
+	n.endpointCnt++
+	n.Unlock()
+}
+
+func (n *network) DecEndpointCnt() {
+	n.Lock()
+	n.endpointCnt--
+	n.Unlock()
 }
 
 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
@@ -115,6 +146,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
 	netMap["name"] = n.name
 	netMap["id"] = string(n.id)
 	netMap["networkType"] = n.networkType
+	netMap["endpointCnt"] = n.endpointCnt
 	netMap["enableIPv6"] = n.enableIPv6
 	netMap["generic"] = n.generic
 	return json.Marshal(netMap)
@@ -129,6 +161,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
 	n.name = netMap["name"].(string)
 	n.id = types.UUID(netMap["id"].(string))
 	n.networkType = netMap["networkType"].(string)
+	n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
 	n.enableIPv6 = netMap["enableIPv6"].(bool)
 	if netMap["generic"] != nil {
 		n.generic = netMap["generic"].(map[string]interface{})
@@ -161,24 +194,51 @@ func (n *network) processOptions(options ...NetworkOption) {
 }
 
 func (n *network) Delete() error {
-	n.ctrlr.Lock()
-	_, ok := n.ctrlr.networks[n.id]
+	var err error
+
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+
+	ctrlr.Lock()
+	_, ok := ctrlr.networks[n.id]
+	ctrlr.Unlock()
+
 	if !ok {
-		n.ctrlr.Unlock()
 		return &UnknownNetworkError{name: n.name, id: string(n.id)}
 	}
 
-	n.Lock()
-	numEps := len(n.endpoints)
-	n.Unlock()
+	numEps := n.EndpointCnt()
 	if numEps != 0 {
-		n.ctrlr.Unlock()
 		return &ActiveEndpointsError{name: n.name, id: string(n.id)}
 	}
 
-	delete(n.ctrlr.networks, n.id)
+	// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
+	// prevent any possible race between endpoint join and network delete
+	if err = ctrlr.deleteNetworkFromStore(n); err != nil {
+		if err == store.ErrKeyModified {
+			return types.InternalErrorf("operation in progress. delete failed for network %s. Please try again.")
+		}
+		return err
+	}
+
+	if err = n.deleteNetwork(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (n *network) deleteNetwork() error {
+	n.Lock()
+	id := n.id
+	d := n.driver
+	n.ctrlr.Lock()
+	delete(n.ctrlr.networks, id)
 	n.ctrlr.Unlock()
-	if err := n.driver.DeleteNetwork(n.id); err != nil {
+	n.Unlock()
+
+	if err := d.DeleteNetwork(n.id); err != nil {
 		// Forbidden Errors should be honored
 		if _, ok := err.(types.ForbiddenError); ok {
 			n.ctrlr.Lock()
@@ -191,12 +251,35 @@ func (n *network) Delete() error {
 	return nil
 }
 
+func (n *network) addEndpoint(ep *endpoint) error {
+	var err error
+	n.Lock()
+	n.endpoints[ep.id] = ep
+	d := n.driver
+	n.Unlock()
+
+	defer func() {
+		if err != nil {
+			n.Lock()
+			delete(n.endpoints, ep.id)
+			n.Unlock()
+		}
+	}()
+
+	err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
+	var err error
 	if name == "" {
 		return nil, ErrInvalidName(name)
 	}
 
-	if _, err := n.EndpointByName(name); err == nil {
+	if _, err = n.EndpointByName(name); err == nil {
 		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
 	}
 
@@ -205,15 +288,37 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 	ep.network = n
 	ep.processOptions(options...)
 
-	d := n.driver
-	err := d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
-	if err != nil {
+	n.Lock()
+	ctrlr := n.ctrlr
+	n.Unlock()
+
+	n.IncEndpointCnt()
+	if err = ctrlr.updateNetworkToStore(n); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			n.DecEndpointCnt()
+			if err = ctrlr.updateNetworkToStore(n); err != nil {
+				log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
+			}
+		}
+	}()
+	if err = n.addEndpoint(ep); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			if e := ep.Delete(); ep != nil {
+				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
+			}
+		}
+	}()
+
+	if err = ctrlr.updateEndpointToStore(ep); err != nil {
 		return nil, err
 	}
 
-	n.Lock()
-	n.endpoints[ep.id] = ep
-	n.Unlock()
 	return ep, nil
 }
 
@@ -271,12 +376,9 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
 	return nil, ErrNoSuchEndpoint(id)
 }
 
-func isReservedNetwork(name string) bool {
-	reserved := []string{"bridge", "none", "host"}
-	for _, r := range reserved {
-		if strings.EqualFold(r, name) {
-			return true
-		}
-	}
-	return false
+func (n *network) isGlobalScoped() (bool, error) {
+	n.Lock()
+	c := n.ctrlr
+	n.Unlock()
+	return c.isDriverGlobalScoped(n.networkType)
 }

+ 292 - 0
libnetwork/store.go

@@ -0,0 +1,292 @@
+package libnetwork
+
+import (
+	"encoding/json"
+	"fmt"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/types"
+)
+
+func (c *controller) initDataStore() error {
+	c.Lock()
+	cfg := c.cfg
+	c.Unlock()
+	if cfg == nil {
+		return fmt.Errorf("datastore initialization requires a valid configuration")
+	}
+
+	store, err := datastore.NewDataStore(&cfg.Datastore)
+	if err != nil {
+		return err
+	}
+	c.Lock()
+	c.store = store
+	c.Unlock()
+	return c.watchStore()
+}
+
+func (c *controller) newNetworkFromStore(n *network) error {
+	n.Lock()
+	n.ctrlr = c
+	n.endpoints = endpointTable{}
+	n.Unlock()
+
+	return c.addNetwork(n)
+}
+
+func (c *controller) updateNetworkToStore(n *network) error {
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. Network %s is not added to the store", n.Name())
+		return nil
+	}
+
+	return cs.PutObjectAtomic(n)
+}
+
+func (c *controller) deleteNetworkFromStore(n *network) error {
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. Network %s is not deleted from datastore", n.Name())
+		return nil
+	}
+
+	if err := cs.DeleteObjectAtomic(n); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
+	n := network{id: nid}
+	if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
+		return nil, err
+	}
+	return &n, nil
+}
+
+func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	id := ep.id
+	ep.Unlock()
+	if n == nil {
+		// Possibly the watch event for the network has not shown up yet
+		// Try to get network from the store
+		nid, err := networkIDFromEndpointKey(key, ep)
+		if err != nil {
+			return err
+		}
+		n, err = c.getNetworkFromStore(nid)
+		if err != nil {
+			return err
+		}
+		if err := c.newNetworkFromStore(n); err != nil {
+			return err
+		}
+		n = c.networks[nid]
+	}
+
+	_, err := n.EndpointByID(string(id))
+	if err != nil {
+		if _, ok := err.(ErrNoSuchEndpoint); ok {
+			return n.addEndpoint(ep)
+		}
+	}
+	return err
+}
+
+func (c *controller) updateEndpointToStore(ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	name := ep.name
+	ep.Unlock()
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. endpoint %s is not added to the store", name)
+		return nil
+	}
+
+	return cs.PutObjectAtomic(ep)
+}
+
+func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
+	ep := endpoint{id: eid}
+	if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
+		return nil, err
+	}
+	return &ep, nil
+}
+
+func (c *controller) deleteEndpointFromStore(ep *endpoint) error {
+	ep.Lock()
+	n := ep.network
+	ep.Unlock()
+	global, err := n.isGlobalScoped()
+	if err != nil || !global {
+		return err
+	}
+
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+	if cs == nil {
+		log.Debugf("datastore not initialized. endpoint %s is not deleted from datastore", ep.Name())
+		return nil
+	}
+
+	if err := cs.DeleteObjectAtomic(ep); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *controller) watchStore() error {
+	c.Lock()
+	cs := c.store
+	c.Unlock()
+
+	nwPairs, err := cs.KVStore().WatchTree(datastore.Key(datastore.NetworkKeyPrefix), nil)
+	if err != nil {
+		return err
+	}
+	epPairs, err := cs.KVStore().WatchTree(datastore.Key(datastore.EndpointKeyPrefix), nil)
+	if err != nil {
+		return err
+	}
+	go func() {
+		for {
+			select {
+			case nws := <-nwPairs:
+				for _, kve := range nws {
+					var n network
+					err := json.Unmarshal(kve.Value, &n)
+					if err != nil {
+						log.Error(err)
+						continue
+					}
+					n.dbIndex = kve.LastIndex
+					c.Lock()
+					existing, ok := c.networks[n.id]
+					c.Unlock()
+					if ok {
+						existing.Lock()
+						// Skip existing network update
+						if existing.dbIndex != n.dbIndex {
+							existing.dbIndex = n.dbIndex
+							existing.endpointCnt = n.endpointCnt
+						}
+						existing.Unlock()
+						continue
+					}
+
+					if err = c.newNetworkFromStore(&n); err != nil {
+						log.Error(err)
+					}
+				}
+			case eps := <-epPairs:
+				for _, epe := range eps {
+					var ep endpoint
+					err := json.Unmarshal(epe.Value, &ep)
+					if err != nil {
+						log.Error(err)
+						continue
+					}
+					ep.dbIndex = epe.LastIndex
+					n, err := c.networkFromEndpointKey(epe.Key, &ep)
+					if err != nil {
+						if _, ok := err.(ErrNoSuchNetwork); !ok {
+							log.Error(err)
+							continue
+						}
+					}
+					if n != nil {
+						ep.network = n.(*network)
+					}
+					if c.processEndpointUpdate(&ep) {
+						err = c.newEndpointFromStore(epe.Key, &ep)
+						if err != nil {
+							log.Error(err)
+						}
+					}
+				}
+			}
+		}
+	}()
+	return nil
+}
+
+func (c *controller) networkFromEndpointKey(key string, ep *endpoint) (Network, error) {
+	nid, err := networkIDFromEndpointKey(key, ep)
+	if err != nil {
+		return nil, err
+	}
+	return c.NetworkByID(string(nid))
+}
+
+func networkIDFromEndpointKey(key string, ep *endpoint) (types.UUID, error) {
+	eKey, err := datastore.ParseKey(key)
+	if err != nil {
+		return types.UUID(""), err
+	}
+	return ep.networkIDFromKey(eKey)
+}
+
+func (c *controller) processEndpointUpdate(ep *endpoint) bool {
+	nw := ep.network
+	if nw == nil {
+		return true
+	}
+	nw.Lock()
+	id := nw.id
+	nw.Unlock()
+
+	c.Lock()
+	n, ok := c.networks[id]
+	c.Unlock()
+	if !ok {
+		return true
+	}
+	existing, _ := n.EndpointByID(string(ep.id))
+	if existing == nil {
+		return true
+	}
+
+	ee := existing.(*endpoint)
+	ee.Lock()
+	if ee.dbIndex != ep.dbIndex {
+		ee.dbIndex = ep.dbIndex
+		if ee.container != nil && ep.container != nil {
+			// we care only about the container id
+			ee.container.id = ep.container.id
+		} else {
+			// we still care only about the container id, but this is a short-cut to communicate join or leave operation
+			ee.container = ep.container
+		}
+	}
+	ee.Unlock()
+
+	return false
+}