mirror of https://github.com/docker/docs.git
Merge pull request #1601 from vieux/docker_discovery
use docker/docker/pkg/discovery and update godeps
This commit is contained in:
commit
254e095f77
|
@ -14,57 +14,62 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd/client",
|
||||
"Comment": "v2.3.0-alpha.0-390-gc70d533",
|
||||
"Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6"
|
||||
"Comment": "v2.3.0-alpha.0-430-g374b14e",
|
||||
"Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd/pkg/pathutil",
|
||||
"Comment": "v2.3.0-alpha.0-390-gc70d533",
|
||||
"Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6"
|
||||
"Comment": "v2.3.0-alpha.0-430-g374b14e",
|
||||
"Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd/pkg/types",
|
||||
"Comment": "v2.3.0-alpha.0-390-gc70d533",
|
||||
"Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6"
|
||||
"Comment": "v2.3.0-alpha.0-430-g374b14e",
|
||||
"Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/filters",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"ImportPath": "github.com/docker/docker/pkg/discovery",
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/ioutils",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/longpath",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/random",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/stringid",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/tlsconfig",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/version",
|
||||
"Comment": "v1.4.1-8996-g7fab931",
|
||||
"Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e"
|
||||
"Comment": "v1.4.1-9107-gf11b6a2",
|
||||
"Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/engine-api/types/filters",
|
||||
"Comment": "v0.2.0",
|
||||
"Rev": "259fce04b5a17bc7a202090d52ca873762fa8b25"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/go-connections/tlsconfig",
|
||||
"Comment": "v0.1.2",
|
||||
"Rev": "4e42727957c146776e5de9cec8c39e4059ed9f20"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/go-units",
|
||||
|
@ -95,8 +100,8 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/consul/api",
|
||||
"Comment": "v0.6.0-121-g68969ce",
|
||||
"Rev": "68969ce5f4499cbe3a4f946917be2e580f1b1936"
|
||||
"Comment": "v0.6.1-11-g562bf11",
|
||||
"Rev": "562bf11e9ff784824f9c5fec0ad3609805e13a3d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-cleanhttp",
|
||||
|
@ -148,7 +153,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/pmezard/go-difflib/difflib",
|
||||
"Rev": "e8554b8641db39598be7f6342874b958f12ae1d4"
|
||||
"Rev": "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/samalba/dockerclient",
|
||||
|
@ -168,13 +173,13 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/assert",
|
||||
"Comment": "v1.0-91-g5b9da39",
|
||||
"Rev": "5b9da39b66e8e994455c2525c4421c8cc00a7f93"
|
||||
"Comment": "v1.1.3",
|
||||
"Rev": "f390dcf405f7b83c997eac1b06768bb9f44dec18"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/mock",
|
||||
"Comment": "v1.0-91-g5b9da39",
|
||||
"Rev": "5b9da39b66e8e994455c2525c4421c8cc00a7f93"
|
||||
"Comment": "v1.1.3",
|
||||
"Rev": "f390dcf405f7b83c997eac1b06768bb9f44dec18"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ugorji/go/codec",
|
||||
|
@ -182,7 +187,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "1ade16a5450925b7496e1031938175d1f5d30d31"
|
||||
"Rev": "4fd4a9fed55e5bdee4a89d6406c2eabe38b60300"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
|
|
41
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md
generated
vendored
Normal file
41
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
page_title: Docker discovery
|
||||
page_description: discovery
|
||||
page_keywords: docker, clustering, discovery
|
||||
---
|
||||
|
||||
# Discovery
|
||||
|
||||
Docker comes with multiple Discovery backends.
|
||||
|
||||
## Backends
|
||||
|
||||
### Using etcd
|
||||
|
||||
Point your Docker Engine instances to a common etcd instance. You can specify
|
||||
the address Docker uses to advertise the node using the `--cluster-advertise`
|
||||
flag.
|
||||
|
||||
```bash
|
||||
$ docker daemon -H=<node_ip:2376> --cluster-advertise=<node_ip:2376> --cluster-store etcd://<etcd_ip1>,<etcd_ip2>/<path>
|
||||
```
|
||||
|
||||
### Using consul
|
||||
|
||||
Point your Docker Engine instances to a common Consul instance. You can specify
|
||||
the address Docker uses to advertise the node using the `--cluster-advertise`
|
||||
flag.
|
||||
|
||||
```bash
|
||||
$ docker daemon -H=<node_ip:2376> --cluster-advertise=<node_ip:2376> --cluster-store consul://<consul_ip>/<path>
|
||||
```
|
||||
|
||||
### Using zookeeper
|
||||
|
||||
Point your Docker Engine instances to a common Zookeeper instance. You can specify
|
||||
the address Docker uses to advertise the node using the `--cluster-advertise`
|
||||
flag.
|
||||
|
||||
```bash
|
||||
$ docker daemon -H=<node_ip:2376> --cluster-advertise=<node_ip:2376> --cluster-store zk://<zk_addr1>,<zk_addr2>/<path>
|
||||
```
|
111
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go
generated
vendored
Normal file
111
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
// Backends is a global map of discovery backends indexed by their
|
||||
// associated scheme.
|
||||
backends map[string]Backend
|
||||
)
|
||||
|
||||
func init() {
|
||||
backends = make(map[string]Backend)
|
||||
}
|
||||
|
||||
// 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 Backend) error {
|
||||
if _, exists := backends[scheme]; exists {
|
||||
return fmt.Errorf("scheme already registered %s", scheme)
|
||||
}
|
||||
log.WithField("name", scheme).Debug("Registering discovery service")
|
||||
backends[scheme] = d
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(rawurl string) (string, string) {
|
||||
parts := strings.SplitN(rawurl, "://", 2)
|
||||
|
||||
// nodes:port,node2:port => nodes://node1:port,node2:port
|
||||
if len(parts) == 1 {
|
||||
return "nodes", parts[0]
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// ParseAdvertise parses the --cluster-advertise daemon config which accepts
|
||||
// <ip-address>:<port> or <interface-name>:<port>
|
||||
func ParseAdvertise(store, advertise string) (string, error) {
|
||||
var (
|
||||
iface *net.Interface
|
||||
addrs []net.Addr
|
||||
err error
|
||||
)
|
||||
|
||||
addr, port, err := net.SplitHostPort(advertise)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid --cluster-advertise configuration: %s: %v", advertise, err)
|
||||
}
|
||||
|
||||
ip := net.ParseIP(addr)
|
||||
// If it is a valid ip-address, use it as is
|
||||
if ip != nil {
|
||||
return advertise, nil
|
||||
}
|
||||
|
||||
// If advertise is a valid interface name, get the valid ipv4 address and use it to advertise
|
||||
ifaceName := addr
|
||||
iface, err = net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid cluster advertise IP address or interface name (%s) : %v", advertise, err)
|
||||
}
|
||||
|
||||
addrs, err = iface.Addrs()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get advertise IP address from interface (%s) : %v", advertise, err)
|
||||
}
|
||||
|
||||
if addrs == nil || len(addrs) == 0 {
|
||||
return "", fmt.Errorf("no available advertise IP address in interface (%s)", advertise)
|
||||
}
|
||||
|
||||
addr = ""
|
||||
for _, a := range addrs {
|
||||
ip, _, err := net.ParseCIDR(a.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error deriving advertise ip-address in interface (%s) : %v", advertise, err)
|
||||
}
|
||||
if ip.To4() == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
addr = ip.String()
|
||||
break
|
||||
}
|
||||
if addr == "" {
|
||||
return "", fmt.Errorf("couldnt find a valid ip-address in interface %s", advertise)
|
||||
}
|
||||
|
||||
addr = fmt.Sprintf("%s:%s", addr, port)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// 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, clusterOpts map[string]string) (Backend, error) {
|
||||
scheme, uri := parse(rawurl)
|
||||
if backend, exists := backends[scheme]; exists {
|
||||
log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service")
|
||||
err := backend.Initialize(uri, heartbeat, ttl, clusterOpts)
|
||||
return backend, err
|
||||
}
|
||||
|
||||
return nil, ErrNotSupported
|
||||
}
|
35
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/discovery.go
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/discovery.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotSupported is returned when a discovery service is not supported.
|
||||
ErrNotSupported = errors.New("discovery service not supported")
|
||||
|
||||
// ErrNotImplemented is returned when discovery feature is not implemented
|
||||
// by discovery backend.
|
||||
ErrNotImplemented = errors.New("not implemented in this discovery service")
|
||||
)
|
||||
|
||||
// Watcher provides watching over a cluster for nodes joining and leaving.
|
||||
type Watcher interface {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Backend is implemented by discovery backends which manage cluster entries.
|
||||
type Backend interface {
|
||||
// Watcher must be provided by every backend.
|
||||
Watcher
|
||||
|
||||
// Initialize the discovery with URIs, a heartbeat, a ttl and optional settings.
|
||||
Initialize(string, time.Duration, time.Duration, map[string]string) error
|
||||
|
||||
// Register to the discovery.
|
||||
Register(string) error
|
||||
}
|
97
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/entry.go
generated
vendored
Normal file
97
Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/entry.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// NewEntry creates a new entry.
|
||||
func NewEntry(url string) (*Entry, error) {
|
||||
host, port, err := net.SplitHostPort(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Entry{host, port}, nil
|
||||
}
|
||||
|
||||
// An Entry represents a host.
|
||||
type Entry struct {
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// String returns the string form of an entry.
|
||||
func (e *Entry) String() string {
|
||||
return fmt.Sprintf("%s:%s", e.Host, e.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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
if len(addr) == 0 {
|
||||
continue
|
||||
}
|
||||
entry, err := NewEntry(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
)
|
||||
|
||||
// Discovery is exported
|
|
@ -7,17 +7,17 @@ import (
|
|||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/docker/libkv"
|
||||
"github.com/docker/libkv/store"
|
||||
"github.com/docker/libkv/store/consul"
|
||||
"github.com/docker/libkv/store/etcd"
|
||||
"github.com/docker/libkv/store/zookeeper"
|
||||
"github.com/docker/swarm/discovery"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDiscoveryPath = "docker/swarm/nodes"
|
||||
defaultDiscoveryPath = "docker/nodes"
|
||||
)
|
||||
|
||||
// Discovery is exported
|
||||
|
@ -41,14 +41,14 @@ func Init() {
|
|||
consul.Register()
|
||||
etcd.Register()
|
||||
|
||||
// Register to internal Swarm discovery service
|
||||
// Register to internal discovery service
|
||||
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 time.Duration, ttl time.Duration, discoveryOpt map[string]string) error {
|
||||
func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) error {
|
||||
var (
|
||||
parts = strings.SplitN(uris, "/", 2)
|
||||
addrs = strings.Split(parts[0], ",")
|
||||
|
@ -65,19 +65,19 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du
|
|||
|
||||
// Use a custom path if specified in discovery options
|
||||
dpath := defaultDiscoveryPath
|
||||
if discoveryOpt["kv.path"] != "" {
|
||||
dpath = discoveryOpt["kv.path"]
|
||||
if clusterOpts["kv.path"] != "" {
|
||||
dpath = clusterOpts["kv.path"]
|
||||
}
|
||||
|
||||
s.path = path.Join(s.prefix, dpath)
|
||||
|
||||
var config *store.Config
|
||||
if discoveryOpt["kv.cacertfile"] != "" && discoveryOpt["kv.certfile"] != "" && discoveryOpt["kv.keyfile"] != "" {
|
||||
log.Debug("Initializing discovery with TLS")
|
||||
if clusterOpts["kv.cacertfile"] != "" && clusterOpts["kv.certfile"] != "" && clusterOpts["kv.keyfile"] != "" {
|
||||
log.Info("Initializing discovery with TLS")
|
||||
tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
|
||||
CAFile: discoveryOpt["kv.cacertfile"],
|
||||
CertFile: discoveryOpt["kv.certfile"],
|
||||
KeyFile: discoveryOpt["kv.keyfile"],
|
||||
CAFile: clusterOpts["kv.cacertfile"],
|
||||
CertFile: clusterOpts["kv.certfile"],
|
||||
KeyFile: clusterOpts["kv.keyfile"],
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -85,15 +85,15 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du
|
|||
config = &store.Config{
|
||||
// Set ClientTLS to trigger https (bug in libkv/etcd)
|
||||
ClientTLS: &store.ClientTLSConfig{
|
||||
CACertFile: discoveryOpt["kv.cacertfile"],
|
||||
CertFile: discoveryOpt["kv.certfile"],
|
||||
KeyFile: discoveryOpt["kv.keyfile"],
|
||||
CACertFile: clusterOpts["kv.cacertfile"],
|
||||
CertFile: clusterOpts["kv.certfile"],
|
||||
KeyFile: clusterOpts["kv.keyfile"],
|
||||
},
|
||||
// The actual TLS config that will be used
|
||||
TLS: tlsConfig,
|
||||
}
|
||||
} else {
|
||||
log.Debug("Initializing discovery without TLS")
|
||||
log.Info("Initializing discovery without TLS")
|
||||
}
|
||||
|
||||
// Creates a new store, will ignore options given
|
||||
|
@ -172,7 +172,6 @@ func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-c
|
|||
time.Sleep(s.heartbeat)
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, errCh
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
)
|
||||
|
||||
// Discovery is exported
|
191
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/docker/engine-api/LICENSE
generated
vendored
Normal file
191
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/docker/engine-api/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015-2016 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
9
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/COPYRIGHT
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/COPYRIGHT
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
Copyright 2009 The Go Authors. All rights reserved. Use of this source code
|
||||
is governed by a BSD-style license that can be found in the LICENSE file.
|
||||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is
|
||||
governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
Copyright 2014 CloudFlare. All rights reserved. Use of this source code is
|
||||
governed by a BSD-style license that can be found in the LICENSE file.
|
32
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/LICENSE
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
As this is fork of the official Go code the same license applies:
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015-2016 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -585,13 +585,15 @@ func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
|||
if len(diff.ToDate) > 0 {
|
||||
toDate = "\t" + diff.ToDate
|
||||
}
|
||||
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
if diff.FromFile != "" || diff.ToFile != "" {
|
||||
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
first, last := g[0], g[len(g)-1]
|
||||
|
@ -710,8 +712,10 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
if len(diff.ToDate) > 0 {
|
||||
toDate = "\t" + diff.ToDate
|
||||
}
|
||||
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if diff.FromFile != "" || diff.ToFile != "" {
|
||||
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
}
|
||||
}
|
||||
|
||||
first, last := g[0], g[len(g)-1]
|
||||
|
|
387
Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
Normal file
387
Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
|
||||
* THIS FILE MUST NOT BE EDITED BY HAND
|
||||
*/
|
||||
|
||||
package assert
|
||||
|
||||
import (
|
||||
|
||||
http "net/http"
|
||||
url "net/url"
|
||||
time "time"
|
||||
)
|
||||
|
||||
|
||||
// Condition uses a Comparison to assert a complex condition.
|
||||
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
|
||||
return Condition(a.t, comp, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Contains asserts that the specified string, list(array, slice...) or map contains the
|
||||
// specified substring or element.
|
||||
//
|
||||
// a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
|
||||
// a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
|
||||
// a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Contains(a.t, s, contains, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// Equal asserts that two objects are equal.
|
||||
//
|
||||
// a.Equal(123, 123, "123 and 123 should be equal")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Equal(a.t, expected, actual, 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(t, err, "An error was expected") {
|
||||
// assert.Equal(t, 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...)
|
||||
}
|
||||
|
||||
|
||||
// EqualValues asserts that two objects are equal or convertable to the same types
|
||||
// and equal.
|
||||
//
|
||||
// a.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 interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if a.Error(err, "An error was expected") {
|
||||
// assert.Equal(t, err, expectedError)
|
||||
// }
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
|
||||
return Error(a.t, err, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Exactly asserts that two objects are equal is value and type.
|
||||
//
|
||||
// a.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 interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Exactly(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Fail reports a failure through
|
||||
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
|
||||
return Fail(a.t, failureMessage, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// FailNow fails test
|
||||
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
|
||||
return FailNow(a.t, failureMessage, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// False asserts that the specified value is false.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// HTTPBodyContains asserts that a specified handler returns a
|
||||
// body that contains a string.
|
||||
//
|
||||
// a.HTTPBodyContains(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, method string, url string, values url.Values, str interface{}) bool {
|
||||
return HTTPBodyContains(a.t, handler, method, url, values, str)
|
||||
}
|
||||
|
||||
|
||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||
// body that does not contain a string.
|
||||
//
|
||||
// a.HTTPBodyNotContains(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, method string, url string, values url.Values, str interface{}) bool {
|
||||
return HTTPBodyNotContains(a.t, handler, method, url, values, str)
|
||||
}
|
||||
|
||||
|
||||
// HTTPError asserts that a specified handler returns an error status code.
|
||||
//
|
||||
// a.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, method string, url string, values url.Values) bool {
|
||||
return HTTPError(a.t, handler, method, url, values)
|
||||
}
|
||||
|
||||
|
||||
// HTTPRedirect asserts that a specified handler returns a redirect status code.
|
||||
//
|
||||
// a.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, method string, url string, values url.Values) bool {
|
||||
return HTTPRedirect(a.t, handler, method, url, values)
|
||||
}
|
||||
|
||||
|
||||
// HTTPSuccess asserts that a specified handler returns a success status code.
|
||||
//
|
||||
// a.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, method string, url string, values url.Values) bool {
|
||||
return HTTPSuccess(a.t, handler, method, url, values)
|
||||
}
|
||||
|
||||
|
||||
// Implements asserts that an object is implemented by the specified interface.
|
||||
//
|
||||
// a.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
|
||||
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Implements(a.t, interfaceObject, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
||||
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
return InDeltaSlice(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 interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
|
||||
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
return InEpsilonSlice(a.t, expected, actual, delta, 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...)
|
||||
}
|
||||
|
||||
|
||||
// JSONEq asserts that two JSON strings are equivalent.
|
||||
//
|
||||
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
return JSONEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if a.NoError(err) {
|
||||
// assert.Equal(t, actualObj, expectedObj)
|
||||
// }
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
||||
return NoError(a.t, err, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
// a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
|
||||
// a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
|
||||
// a.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 interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||
return NotContains(a.t, s, contains, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// 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 a.NotEmpty(obj) {
|
||||
// assert.Equal(t, "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...)
|
||||
}
|
||||
|
||||
|
||||
// NotEqual asserts that the specified values are NOT equal.
|
||||
//
|
||||
// a.NotEqual(obj1, obj2, "two objects shouldn't be equal")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
return NotEqual(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// NotNil asserts that the specified object is not nil.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// NotRegexp asserts that a specified regexp does not match a string.
|
||||
//
|
||||
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
||||
// a.NotRegexp("^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...)
|
||||
}
|
||||
|
||||
|
||||
// NotZero asserts that i is not the zero value for its type and returns the truth.
|
||||
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
return NotZero(a.t, i, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Panics asserts that the code inside the specified PanicTestFunc panics.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// Regexp asserts that a specified regexp matches a string.
|
||||
//
|
||||
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
||||
// a.Regexp("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...)
|
||||
}
|
||||
|
||||
|
||||
// True asserts that the specified value is true.
|
||||
//
|
||||
// a.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...)
|
||||
}
|
||||
|
||||
|
||||
// WithinDuration asserts that the two times are within duration delta of each other.
|
||||
//
|
||||
// a.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 time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
||||
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
||||
}
|
||||
|
||||
|
||||
// Zero asserts that i is the zero value for its type and returns the truth.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Zero(a.t, i, msgAndArgs...)
|
||||
}
|
4
Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{{.CommentWithoutT "a"}}
|
||||
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
|
||||
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
||||
}
|
|
@ -181,6 +181,28 @@ func indentMessageLines(message string, tabs int) string {
|
|||
return outBuf.String()
|
||||
}
|
||||
|
||||
type failNower interface {
|
||||
FailNow()
|
||||
}
|
||||
|
||||
// FailNow fails test
|
||||
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||
Fail(t, failureMessage, msgAndArgs...)
|
||||
|
||||
// We cannot extend TestingT with FailNow() and
|
||||
// maintain backwards compatibility, so we fallback
|
||||
// to panicking when FailNow is not available in
|
||||
// TestingT.
|
||||
// See issue #263
|
||||
|
||||
if t, ok := t.(failNower); ok {
|
||||
t.FailNow()
|
||||
} else {
|
||||
panic("test failed and t is missing `FailNow()`")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Fail reports a failure through
|
||||
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||
|
||||
|
@ -363,6 +385,11 @@ func isEmpty(object interface{}) bool {
|
|||
{
|
||||
return (objValue.Len() == 0)
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch object.(type) {
|
||||
case time.Time:
|
||||
return object.(time.Time).IsZero()
|
||||
}
|
||||
case reflect.Ptr:
|
||||
{
|
||||
if objValue.IsNil() {
|
||||
|
@ -739,42 +766,40 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn
|
|||
return true
|
||||
}
|
||||
|
||||
// min(|expected|, |actual|) * epsilon
|
||||
func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
|
||||
func calcRelativeError(expected, actual interface{}) (float64, error) {
|
||||
af, aok := toFloat(expected)
|
||||
if !aok {
|
||||
return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
|
||||
}
|
||||
if af == 0 {
|
||||
return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
|
||||
}
|
||||
bf, bok := toFloat(actual)
|
||||
|
||||
if !aok || !bok {
|
||||
// invalid input
|
||||
return 0
|
||||
if !bok {
|
||||
return 0, fmt.Errorf("expected value %q cannot be converted to float", actual)
|
||||
}
|
||||
|
||||
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
|
||||
return math.Abs(af-bf) / math.Abs(af), nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
actualEpsilon, err := calcRelativeError(expected, actual)
|
||||
if err != nil {
|
||||
return Fail(t, err.Error(), msgAndArgs...)
|
||||
}
|
||||
if actualEpsilon > epsilon {
|
||||
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
|
||||
" < %#v (actual)", actualEpsilon, epsilon), msgAndArgs...)
|
||||
}
|
||||
|
||||
return InDelta(t, expected, actual, delta, msgAndArgs...)
|
||||
return true
|
||||
}
|
||||
|
||||
// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
|
||||
func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
||||
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||
if expected == nil || actual == nil ||
|
||||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
||||
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
||||
|
@ -785,7 +810,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msg
|
|||
expectedSlice := reflect.ValueOf(expected)
|
||||
|
||||
for i := 0; i < actualSlice.Len(); i++ {
|
||||
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
|
||||
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
|
||||
if !result {
|
||||
return result
|
||||
}
|
||||
|
|
270
Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
270
Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
|
@ -1,7 +1,5 @@
|
|||
package assert
|
||||
|
||||
import "time"
|
||||
|
||||
// Assertions provides assertion methods around the
|
||||
// TestingT interface.
|
||||
type Assertions struct {
|
||||
|
@ -15,270 +13,4 @@ func New(t TestingT) *Assertions {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 false.
|
||||
//
|
||||
// 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...)
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type and returns the truth.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
return Zero(a.t, i, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotZero asserts that i is not the zero value for its type and returns the truth.
|
||||
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
return NotZero(a.t, i, msgAndArgs...)
|
||||
}
|
||||
|
||||
// JSONEq asserts that two JSON strings are equivalent.
|
||||
//
|
||||
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
return JSONEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl
|
||||
|
|
|
@ -104,54 +104,3 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin
|
|||
|
||||
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, method, url string, values url.Values) bool {
|
||||
return HTTPSuccess(a.t, handler, method, 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, method, url string, values url.Values) bool {
|
||||
return HTTPRedirect(a.t, handler, method, 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, method, url string, values url.Values) bool {
|
||||
return HTTPError(a.t, handler, method, 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, method, url string, values url.Values, str interface{}) bool {
|
||||
return HTTPBodyContains(a.t, handler, method, 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, method, url string, values url.Values, str interface{}) bool {
|
||||
return HTTPBodyNotContains(a.t, handler, method, url, values, str)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Provides a system by which it is possible to mock your objects and verify calls are happening as expected.
|
||||
// Package mock provides a system by which it is possible to mock your objects
|
||||
// and verify calls are happening as expected.
|
||||
//
|
||||
// Example Usage
|
||||
//
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
type TestingT interface {
|
||||
Logf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
FailNow()
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -64,64 +65,67 @@ func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *C
|
|||
}
|
||||
}
|
||||
|
||||
func (self *Call) lock() {
|
||||
self.Parent.mutex.Lock()
|
||||
func (c *Call) lock() {
|
||||
c.Parent.mutex.Lock()
|
||||
}
|
||||
|
||||
func (self *Call) unlock() {
|
||||
self.Parent.mutex.Unlock()
|
||||
func (c *Call) unlock() {
|
||||
c.Parent.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (self *Call) Return(returnArguments ...interface{}) *Call {
|
||||
self.lock()
|
||||
defer self.unlock()
|
||||
// Return specifies the return arguments for the expectation.
|
||||
//
|
||||
// Mock.On("DoSomething").Return(errors.New("failed"))
|
||||
func (c *Call) Return(returnArguments ...interface{}) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
|
||||
self.ReturnArguments = returnArguments
|
||||
c.ReturnArguments = returnArguments
|
||||
|
||||
return self
|
||||
return c
|
||||
}
|
||||
|
||||
// Once indicates that that the mock should only return the value once.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
|
||||
func (self *Call) Once() *Call {
|
||||
return self.Times(1)
|
||||
func (c *Call) Once() *Call {
|
||||
return c.Times(1)
|
||||
}
|
||||
|
||||
// Twice indicates that that the mock should only return the value twice.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
|
||||
func (self *Call) Twice() *Call {
|
||||
return self.Times(2)
|
||||
func (c *Call) Twice() *Call {
|
||||
return c.Times(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 (self *Call) Times(i int) *Call {
|
||||
self.lock()
|
||||
defer self.unlock()
|
||||
self.Repeatability = i
|
||||
return self
|
||||
func (c *Call) Times(i int) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.Repeatability = i
|
||||
return c
|
||||
}
|
||||
|
||||
// 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 (self *Call) WaitUntil(w <-chan time.Time) *Call {
|
||||
self.lock()
|
||||
defer self.unlock()
|
||||
self.WaitFor = w
|
||||
return self
|
||||
func (c *Call) WaitUntil(w <-chan time.Time) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.WaitFor = w
|
||||
return c
|
||||
}
|
||||
|
||||
// After sets how long to block until the call returns
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
|
||||
func (self *Call) After(d time.Duration) *Call {
|
||||
return self.WaitUntil(time.After(d))
|
||||
func (c *Call) After(d time.Duration) *Call {
|
||||
return c.WaitUntil(time.After(d))
|
||||
}
|
||||
|
||||
// Run sets a handler to be called before returning. It can be used when
|
||||
|
@ -132,11 +136,11 @@ func (self *Call) After(d time.Duration) *Call {
|
|||
// arg := args.Get(0).(*map[string]interface{})
|
||||
// arg["foo"] = "bar"
|
||||
// })
|
||||
func (self *Call) Run(fn func(Arguments)) *Call {
|
||||
self.lock()
|
||||
defer self.unlock()
|
||||
self.RunFn = fn
|
||||
return self
|
||||
func (c *Call) Run(fn func(Arguments)) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.RunFn = fn
|
||||
return c
|
||||
}
|
||||
|
||||
// On chains a new expectation description onto the mocked interface. This
|
||||
|
@ -145,8 +149,8 @@ func (self *Call) Run(fn func(Arguments)) *Call {
|
|||
// Mock.
|
||||
// On("MyMethod", 1).Return(nil).
|
||||
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
|
||||
func (self *Call) On(methodName string, arguments ...interface{}) *Call {
|
||||
return self.Parent.On(methodName, arguments...)
|
||||
func (c *Call) On(methodName string, arguments ...interface{}) *Call {
|
||||
return c.Parent.On(methodName, arguments...)
|
||||
}
|
||||
|
||||
// Mock is the workhorse used to track activity on another object.
|
||||
|
@ -186,17 +190,17 @@ func (m *Mock) TestData() objx.Map {
|
|||
// being called.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2)
|
||||
func (self *Mock) On(methodName string, arguments ...interface{}) *Call {
|
||||
func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
self.mutex.Lock()
|
||||
defer self.mutex.Unlock()
|
||||
c := newCall(self, methodName, arguments...)
|
||||
self.ExpectedCalls = append(self.ExpectedCalls, c)
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
c := newCall(m, methodName, arguments...)
|
||||
m.ExpectedCalls = append(m.ExpectedCalls, c)
|
||||
return c
|
||||
}
|
||||
|
||||
|
@ -222,7 +226,7 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *
|
|||
|
||||
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
|
||||
diffCount := 0
|
||||
var closestCall *Call = nil
|
||||
var closestCall *Call
|
||||
|
||||
for _, call := range m.expectedCalls() {
|
||||
if call.Method == method {
|
||||
|
@ -245,7 +249,7 @@ func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *
|
|||
|
||||
func callString(method string, arguments Arguments, includeArgumentValues bool) string {
|
||||
|
||||
var argValsString string = ""
|
||||
var argValsString string
|
||||
if includeArgumentValues {
|
||||
var argVals []string
|
||||
for argIndex, arg := range arguments {
|
||||
|
@ -303,7 +307,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
|
|||
call.Repeatability = -1
|
||||
|
||||
case call.Repeatability > 1:
|
||||
call.Repeatability -= 1
|
||||
call.Repeatability--
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
}
|
||||
|
@ -334,7 +338,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
|
|||
//
|
||||
// Calls may have occurred in any order.
|
||||
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
|
||||
var success bool = true
|
||||
var success = true
|
||||
for _, obj := range testObjects {
|
||||
mockObj := obj.(Mock)
|
||||
success = success && mockObj.AssertExpectations(t)
|
||||
|
@ -345,8 +349,8 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
|
|||
// 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
|
||||
var somethingMissing bool
|
||||
var failedExpectations int
|
||||
|
||||
// iterate through each expectation
|
||||
expectedCalls := m.expectedCalls()
|
||||
|
@ -376,7 +380,7 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
|
|||
|
||||
// AssertNumberOfCalls asserts that the method was called expectedCalls times.
|
||||
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
|
||||
var actualCalls int = 0
|
||||
var actualCalls int
|
||||
for _, call := range m.calls() {
|
||||
if call.Method == methodName {
|
||||
actualCalls++
|
||||
|
@ -440,8 +444,8 @@ func (m *Mock) calls() []Call {
|
|||
type Arguments []interface{}
|
||||
|
||||
const (
|
||||
// The "any" argument. Used in Diff and Assert when
|
||||
// the argument being tested shouldn't be taken into consideration.
|
||||
// Anything is used in Diff and Assert when the argument being tested
|
||||
// shouldn't be taken into consideration.
|
||||
Anything string = "mock.Anything"
|
||||
)
|
||||
|
||||
|
@ -471,9 +475,8 @@ func (f argumentMatcher) Matches(argument interface{}) bool {
|
|||
if reflect.TypeOf(argument).AssignableTo(expectType) {
|
||||
result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)})
|
||||
return result[0].Bool()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f argumentMatcher) String() string {
|
||||
|
@ -531,10 +534,10 @@ func (args Arguments) Is(objects ...interface{}) bool {
|
|||
// Returns the diff string and number of differences found.
|
||||
func (args Arguments) Diff(objects []interface{}) (string, int) {
|
||||
|
||||
var output string = "\n"
|
||||
var output = "\n"
|
||||
var differences int
|
||||
|
||||
var maxArgCount int = len(args)
|
||||
var maxArgCount = len(args)
|
||||
if len(objects) > maxArgCount {
|
||||
maxArgCount = len(objects)
|
||||
}
|
||||
|
@ -629,7 +632,7 @@ func (args Arguments) String(indexOrNil ...int) string {
|
|||
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 index = indexOrNil[0]
|
||||
var s string
|
||||
var ok bool
|
||||
if s, ok = args.Get(index).(string); !ok {
|
||||
|
|
13
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
27
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2013, Patrick Mezard
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md
generated
vendored
Normal file
|
@ -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.
|
|
@ -14,7 +14,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
dockerfilters "github.com/docker/docker/api/types/filters"
|
||||
dockerfilters "github.com/docker/engine-api/types/filters"
|
||||
"github.com/docker/swarm/cluster"
|
||||
"github.com/docker/swarm/version"
|
||||
"github.com/gorilla/mux"
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
)
|
||||
|
||||
func checkAddrFormat(addr string) bool {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
)
|
||||
|
||||
func list(c *cli.Context) {
|
||||
|
|
|
@ -11,12 +11,12 @@ import (
|
|||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
kvdiscovery "github.com/docker/docker/pkg/discovery/kv"
|
||||
"github.com/docker/swarm/api"
|
||||
"github.com/docker/swarm/cluster"
|
||||
"github.com/docker/swarm/cluster/mesos"
|
||||
"github.com/docker/swarm/cluster/swarm"
|
||||
"github.com/docker/swarm/discovery"
|
||||
kvdiscovery "github.com/docker/swarm/discovery/kv"
|
||||
"github.com/docker/swarm/leadership"
|
||||
"github.com/docker/swarm/scheduler"
|
||||
"github.com/docker/swarm/scheduler/filter"
|
||||
|
@ -98,7 +98,7 @@ func loadTLSConfig(ca, cert, key string, verify bool) (*tls.Config, error) {
|
|||
}
|
||||
|
||||
// Initialize the discovery service.
|
||||
func createDiscovery(uri string, c *cli.Context, discoveryOpt []string) discovery.Discovery {
|
||||
func createDiscovery(uri string, c *cli.Context, discoveryOpt []string) discovery.Backend {
|
||||
hb, err := time.ParseDuration(c.String("heartbeat"))
|
||||
if err != nil {
|
||||
log.Fatalf("invalid --heartbeat: %v", err)
|
||||
|
@ -126,10 +126,13 @@ func getDiscoveryOpt(c *cli.Context) map[string]string {
|
|||
kvpair := strings.SplitN(option, "=", 2)
|
||||
options[kvpair[0]] = kvpair[1]
|
||||
}
|
||||
if _, ok := options["kv.path"]; !ok {
|
||||
options["kv.path"] = "docker/swarm/nodes"
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func setupReplication(c *cli.Context, cluster cluster.Cluster, server *api.Server, discovery discovery.Discovery, addr string, leaderTTL time.Duration, tlsConfig *tls.Config) {
|
||||
func setupReplication(c *cli.Context, cluster cluster.Cluster, server *api.Server, discovery discovery.Backend, addr string, leaderTTL time.Duration, tlsConfig *tls.Config) {
|
||||
kvDiscovery, ok := discovery.(*kvdiscovery.Discovery)
|
||||
if !ok {
|
||||
log.Fatal("Leader election is only supported with consul, etcd and zookeeper discovery.")
|
||||
|
|
|
@ -3,7 +3,7 @@ package cluster
|
|||
import (
|
||||
"strings"
|
||||
|
||||
dockerfilters "github.com/docker/docker/api/types/filters"
|
||||
dockerfilters "github.com/docker/engine-api/types/filters"
|
||||
"github.com/samalba/dockerclient"
|
||||
)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package cluster
|
|||
import (
|
||||
"testing"
|
||||
|
||||
dockerfilters "github.com/docker/docker/api/types/filters"
|
||||
dockerfilters "github.com/docker/engine-api/types/filters"
|
||||
"github.com/samalba/dockerclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/docker/swarm/cluster"
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/swarm/scheduler"
|
||||
"github.com/docker/swarm/scheduler/node"
|
||||
"github.com/samalba/dockerclient"
|
||||
|
@ -54,7 +54,7 @@ type Cluster struct {
|
|||
engines map[string]*cluster.Engine
|
||||
pendingEngines map[string]*cluster.Engine
|
||||
scheduler *scheduler.Scheduler
|
||||
discovery discovery.Discovery
|
||||
discovery discovery.Backend
|
||||
pendingContainers map[string]*pendingContainer
|
||||
|
||||
overcommitRatio float64
|
||||
|
@ -63,7 +63,7 @@ type Cluster struct {
|
|||
}
|
||||
|
||||
// NewCluster is exported
|
||||
func NewCluster(scheduler *scheduler.Scheduler, TLSConfig *tls.Config, discovery discovery.Discovery, options cluster.DriverOpts, engineOptions *cluster.EngineOpts) (cluster.Cluster, error) {
|
||||
func NewCluster(scheduler *scheduler.Scheduler, TLSConfig *tls.Config, discovery discovery.Backend, options cluster.DriverOpts, engineOptions *cluster.EngineOpts) (cluster.Cluster, error) {
|
||||
log.WithFields(log.Fields{"name": "swarm"}).Debug("Initializing cluster")
|
||||
|
||||
cluster := &Cluster{
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// An Entry represents a swarm host.
|
||||
type Entry struct {
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
// NewEntry creates a new entry.
|
||||
func NewEntry(url string) (*Entry, error) {
|
||||
host, port, err := net.SplitHostPort(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Entry{host, port}, nil
|
||||
}
|
||||
|
||||
// String returns the string form of an entry.
|
||||
func (e *Entry) String() string {
|
||||
return fmt.Sprintf("%s:%s", e.Host, e.Port)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 the discovery with URIs, a heartbeat, a ttl and optional settings.
|
||||
Initialize(string, time.Duration, time.Duration, map[string]string) 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 returned when a discovery service is not supported.
|
||||
ErrNotSupported = errors.New("discovery service not supported")
|
||||
// ErrNotImplemented is returned when discovery feature is not implemented
|
||||
// by discovery backend.
|
||||
ErrNotImplemented = errors.New("not implemented in this discovery service")
|
||||
)
|
||||
|
||||
func init() {
|
||||
discoveries = make(map[string]Discovery)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
log.WithField("name", scheme).Debug("Registering discovery service")
|
||||
discoveries[scheme] = d
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(rawurl string) (string, string) {
|
||||
parts := strings.SplitN(rawurl, "://", 2)
|
||||
|
||||
// nodes:port,node2:port => nodes://node1:port,node2:port
|
||||
if len(parts) == 1 {
|
||||
return "nodes", parts[0]
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// 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, discoveryOpt map[string]string) (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, ttl, discoveryOpt)
|
||||
return discovery, err
|
||||
}
|
||||
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
if len(addr) == 0 {
|
||||
continue
|
||||
}
|
||||
entry, err := NewEntry(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewEntry(t *testing.T) {
|
||||
entry, err := NewEntry("127.0.0.1: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)
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
scheme, uri := parse("127.0.0.1:2375")
|
||||
assert.Equal(t, scheme, "nodes")
|
||||
assert.Equal(t, uri, "127.0.0.1:2375")
|
||||
|
||||
scheme, uri = parse("localhost:2375")
|
||||
assert.Equal(t, scheme, "nodes")
|
||||
assert.Equal(t, uri, "localhost:2375")
|
||||
|
||||
scheme, uri = parse("scheme://127.0.0.1:2375")
|
||||
assert.Equal(t, scheme, "scheme")
|
||||
assert.Equal(t, uri, "127.0.0.1:2375")
|
||||
|
||||
scheme, uri = parse("scheme://localhost:2375")
|
||||
assert.Equal(t, scheme, "scheme")
|
||||
assert.Equal(t, uri, "localhost:2375")
|
||||
|
||||
scheme, uri = parse("")
|
||||
assert.Equal(t, scheme, "nodes")
|
||||
assert.Equal(t, uri, "")
|
||||
}
|
||||
|
||||
func TestCreateEntries(t *testing.T) {
|
||||
entries, err := CreateEntries(nil)
|
||||
assert.Equal(t, entries, Entries{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
entries, err = CreateEntries([]string{"127.0.0.1:2375", "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))
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
d := &Discovery{}
|
||||
d.Initialize("/path/to/file", 1000, 0, nil)
|
||||
assert.Equal(t, d.path, "/path/to/file")
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
d, err := discovery.New("file:///path/to/file", 0, 0, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, d.(*Discovery).path, "/path/to/file")
|
||||
}
|
||||
|
||||
func TestContent(t *testing.T) {
|
||||
data := `
|
||||
1.1.1.[1:2]:1111
|
||||
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")
|
||||
assert.Equal(t, ips[3], "2.2.2.3:2222")
|
||||
assert.Equal(t, ips[4], "2.2.2.4:2222")
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
discovery := &Discovery{path: "/path/to/file"}
|
||||
assert.Error(t, discovery.Register("0.0.0.0"))
|
||||
}
|
||||
|
||||
func TestParsingContentsWithComments(t *testing.T) {
|
||||
data := `
|
||||
### test ###
|
||||
1.1.1.1:1111 # inline comment
|
||||
# 2.2.2.2:2222
|
||||
### empty line with comment
|
||||
3.3.3.3:3333
|
||||
### test ###
|
||||
`
|
||||
ips := parseFileContent([]byte(data))
|
||||
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, nil)
|
||||
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)
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGeneratorNotGenerate(t *testing.T) {
|
||||
ips := Generate("127.0.0.1")
|
||||
assert.Equal(t, len(ips), 1)
|
||||
assert.Equal(t, ips[0], "127.0.0.1")
|
||||
}
|
||||
|
||||
func TestGeneratorWithPortNotGenerate(t *testing.T) {
|
||||
ips := Generate("127.0.0.1:8080")
|
||||
assert.Equal(t, len(ips), 1)
|
||||
assert.Equal(t, ips[0], "127.0.0.1:8080")
|
||||
}
|
||||
|
||||
func TestGeneratorMatchFailedNotGenerate(t *testing.T) {
|
||||
ips := Generate("127.0.0.[1]")
|
||||
assert.Equal(t, len(ips), 1)
|
||||
assert.Equal(t, ips[0], "127.0.0.[1]")
|
||||
}
|
||||
|
||||
func TestGeneratorWithPort(t *testing.T) {
|
||||
ips := Generate("127.0.0.[1:11]:2375")
|
||||
assert.Equal(t, len(ips), 11)
|
||||
assert.Equal(t, ips[0], "127.0.0.1:2375")
|
||||
assert.Equal(t, ips[1], "127.0.0.2:2375")
|
||||
assert.Equal(t, ips[2], "127.0.0.3:2375")
|
||||
assert.Equal(t, ips[3], "127.0.0.4:2375")
|
||||
assert.Equal(t, ips[4], "127.0.0.5:2375")
|
||||
assert.Equal(t, ips[5], "127.0.0.6:2375")
|
||||
assert.Equal(t, ips[6], "127.0.0.7:2375")
|
||||
assert.Equal(t, ips[7], "127.0.0.8:2375")
|
||||
assert.Equal(t, ips[8], "127.0.0.9:2375")
|
||||
assert.Equal(t, ips[9], "127.0.0.10:2375")
|
||||
assert.Equal(t, ips[10], "127.0.0.11:2375")
|
||||
}
|
||||
|
||||
func TestGenerateWithMalformedInputAtRangeStart(t *testing.T) {
|
||||
malformedInput := "127.0.0.[x:11]:2375"
|
||||
ips := Generate(malformedInput)
|
||||
assert.Equal(t, len(ips), 1)
|
||||
assert.Equal(t, ips[0], malformedInput)
|
||||
}
|
||||
|
||||
func TestGenerateWithMalformedInputAtRangeEnd(t *testing.T) {
|
||||
malformedInput := "127.0.0.[1:x]:2375"
|
||||
ips := Generate(malformedInput)
|
||||
assert.Equal(t, len(ips), 1)
|
||||
assert.Equal(t, ips[0], malformedInput)
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
package kv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/libkv"
|
||||
"github.com/docker/libkv/store"
|
||||
libkvmock "github.com/docker/libkv/store/mock"
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
storeMock, err := libkvmock.New([]string{"127.0.0.1"}, nil)
|
||||
assert.NotNil(t, storeMock)
|
||||
assert.NoError(t, err)
|
||||
|
||||
d := &Discovery{backend: store.CONSUL}
|
||||
d.Initialize("127.0.0.1", 0, 0, nil)
|
||||
d.store = storeMock
|
||||
|
||||
s := d.store.(*libkvmock.Mock)
|
||||
assert.Len(t, s.Endpoints, 1)
|
||||
assert.Equal(t, s.Endpoints[0], "127.0.0.1")
|
||||
assert.Equal(t, d.path, defaultDiscoveryPath)
|
||||
|
||||
storeMock, err = libkvmock.New([]string{"127.0.0.1:1234"}, nil)
|
||||
assert.NotNil(t, storeMock)
|
||||
assert.NoError(t, err)
|
||||
|
||||
d = &Discovery{backend: store.CONSUL}
|
||||
d.Initialize("127.0.0.1:1234/path", 0, 0, nil)
|
||||
d.store = storeMock
|
||||
|
||||
s = d.store.(*libkvmock.Mock)
|
||||
assert.Len(t, s.Endpoints, 1)
|
||||
assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
|
||||
assert.Equal(t, d.path, "path/"+defaultDiscoveryPath)
|
||||
|
||||
storeMock, err = libkvmock.New([]string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"}, nil)
|
||||
assert.NotNil(t, storeMock)
|
||||
assert.NoError(t, err)
|
||||
|
||||
d = &Discovery{backend: store.CONSUL}
|
||||
d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0, nil)
|
||||
d.store = storeMock
|
||||
|
||||
s = d.store.(*libkvmock.Mock)
|
||||
if 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/"+defaultDiscoveryPath)
|
||||
}
|
||||
|
||||
func TestInitializeWithCerts(t *testing.T) {
|
||||
cert := `-----BEGIN CERTIFICATE-----
|
||||
MIIDCDCCAfKgAwIBAgIICifG7YeiQOEwCwYJKoZIhvcNAQELMBIxEDAOBgNVBAMT
|
||||
B1Rlc3QgQ0EwHhcNMTUxMDAxMjMwMDAwWhcNMjAwOTI5MjMwMDAwWjASMRAwDgYD
|
||||
VQQDEwdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wRC
|
||||
O+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4+zE9h80aC4hz+6caRpds
|
||||
+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhRSoSi3nY+B7F2E8cuz14q
|
||||
V2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZrpXUyXxAvzXfpFXo1RhSb
|
||||
UywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUerVYrCPq8vqfn//01qz55
|
||||
Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHojxOpXTBepUCIJLbtNnWFT
|
||||
V44t9gh5IqIWtoBReQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAAYwEgYDVR0TAQH/
|
||||
BAgwBgEB/wIBAjAdBgNVHQ4EFgQUZKUI8IIjIww7X/6hvwggQK4bD24wHwYDVR0j
|
||||
BBgwFoAUZKUI8IIjIww7X/6hvwggQK4bD24wCwYJKoZIhvcNAQELA4IBAQDES2cz
|
||||
7sCQfDCxCIWH7X8kpi/JWExzUyQEJ0rBzN1m3/x8ySRxtXyGekimBqQwQdFqlwMI
|
||||
xzAQKkh3ue8tNSzRbwqMSyH14N1KrSxYS9e9szJHfUasoTpQGPmDmGIoRJuq1h6M
|
||||
ej5x1SCJ7GWCR6xEXKUIE9OftXm9TdFzWa7Ja3OHz/mXteii8VXDuZ5ACq6EE5bY
|
||||
8sP4gcICfJ5fTrpTlk9FIqEWWQrCGa5wk95PGEj+GJpNogjXQ97wVoo/Y3p1brEn
|
||||
t5zjN9PAq4H1fuCMdNNA+p1DHNwd+ELTxcMAnb2ajwHvV6lKPXutrTFc4umJToBX
|
||||
FpTxDmJHEV4bzUzh
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
key := `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA1wRCO+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4
|
||||
+zE9h80aC4hz+6caRpds+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhR
|
||||
SoSi3nY+B7F2E8cuz14qV2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZr
|
||||
pXUyXxAvzXfpFXo1RhSbUywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUe
|
||||
rVYrCPq8vqfn//01qz55Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHoj
|
||||
xOpXTBepUCIJLbtNnWFTV44t9gh5IqIWtoBReQIDAQABAoIBAHSWipORGp/uKFXj
|
||||
i/mut776x8ofsAxhnLBARQr93ID+i49W8H7EJGkOfaDjTICYC1dbpGrri61qk8sx
|
||||
qX7p3v/5NzKwOIfEpirgwVIqSNYe/ncbxnhxkx6tXtUtFKmEx40JskvSpSYAhmmO
|
||||
1XSx0E/PWaEN/nLgX/f1eWJIlxlQkk3QeqL+FGbCXI48DEtlJ9+MzMu4pAwZTpj5
|
||||
5qtXo5JJ0jRGfJVPAOznRsYqv864AhMdMIWguzk6EGnbaCWwPcfcn+h9a5LMdony
|
||||
MDHfBS7bb5tkF3+AfnVY3IBMVx7YlsD9eAyajlgiKu4zLbwTRHjXgShy+4Oussz0
|
||||
ugNGnkECgYEA/hi+McrZC8C4gg6XqK8+9joD8tnyDZDz88BQB7CZqABUSwvjDqlP
|
||||
L8hcwo/lzvjBNYGkqaFPUICGWKjeCtd8pPS2DCVXxDQX4aHF1vUur0uYNncJiV3N
|
||||
XQz4Iemsa6wnKf6M67b5vMXICw7dw0HZCdIHD1hnhdtDz0uVpeevLZ8CgYEA2KCT
|
||||
Y43lorjrbCgMqtlefkr3GJA9dey+hTzCiWEOOqn9RqGoEGUday0sKhiLofOgmN2B
|
||||
LEukpKIey8s+Q/cb6lReajDVPDsMweX8i7hz3Wa4Ugp4Xa5BpHqu8qIAE2JUZ7bU
|
||||
t88aQAYE58pUF+/Lq1QzAQdrjjzQBx6SrBxieecCgYEAvukoPZEC8mmiN1VvbTX+
|
||||
QFHmlZha3QaDxChB+QUe7bMRojEUL/fVnzkTOLuVFqSfxevaI/km9n0ac5KtAchV
|
||||
xjp2bTnBb5EUQFqjopYktWA+xO07JRJtMfSEmjZPbbay1kKC7rdTfBm961EIHaRj
|
||||
xZUf6M+rOE8964oGrdgdLlECgYEA046GQmx6fh7/82FtdZDRQp9tj3SWQUtSiQZc
|
||||
qhO59Lq8mjUXz+MgBuJXxkiwXRpzlbaFB0Bca1fUoYw8o915SrDYf/Zu2OKGQ/qa
|
||||
V81sgiVmDuEgycR7YOlbX6OsVUHrUlpwhY3hgfMe6UtkMvhBvHF/WhroBEIJm1pV
|
||||
PXZ/CbMCgYEApNWVktFBjOaYfY6SNn4iSts1jgsQbbpglg3kT7PLKjCAhI6lNsbk
|
||||
dyT7ut01PL6RaW4SeQWtrJIVQaM6vF3pprMKqlc5XihOGAmVqH7rQx9rtQB5TicL
|
||||
BFrwkQE4HQtQBV60hYQUzzlSk44VFDz+jxIEtacRHaomDRh2FtOTz+I=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
certFile, err := ioutil.TempFile("", "cert")
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(certFile.Name())
|
||||
certFile.Write([]byte(cert))
|
||||
certFile.Close()
|
||||
keyFile, err := ioutil.TempFile("", "key")
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(keyFile.Name())
|
||||
keyFile.Write([]byte(key))
|
||||
keyFile.Close()
|
||||
|
||||
libkv.AddStore("mock", libkvmock.New)
|
||||
d := &Discovery{backend: "mock"}
|
||||
err = d.Initialize("127.0.0.3:1234", 0, 0, map[string]string{
|
||||
"kv.cacertfile": certFile.Name(),
|
||||
"kv.certfile": certFile.Name(),
|
||||
"kv.keyfile": keyFile.Name(),
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
s := d.store.(*libkvmock.Mock)
|
||||
assert.Equal(t, s.Options.ClientTLS.CACertFile, certFile.Name())
|
||||
assert.Equal(t, s.Options.ClientTLS.CertFile, certFile.Name())
|
||||
assert.Equal(t, s.Options.ClientTLS.KeyFile, keyFile.Name())
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
storeMock, err := libkvmock.New([]string{"127.0.0.1:1234"}, nil)
|
||||
assert.NotNil(t, storeMock)
|
||||
assert.NoError(t, err)
|
||||
|
||||
d := &Discovery{backend: store.CONSUL}
|
||||
d.Initialize("127.0.0.1:1234/path", 0, 0, nil)
|
||||
d.store = storeMock
|
||||
|
||||
s := d.store.(*libkvmock.Mock)
|
||||
mockCh := make(chan []*store.KVPair)
|
||||
|
||||
// The first watch will fail on those three calls
|
||||
s.On("Exists", "path/"+defaultDiscoveryPath).Return(false, errors.New("test error"))
|
||||
s.On("Put", "path/"+defaultDiscoveryPath, mock.Anything, mock.Anything).Return(errors.New("test error"))
|
||||
s.On("WatchTree", "path/"+defaultDiscoveryPath, mock.Anything).Return(mockCh, errors.New("test error")).Once()
|
||||
|
||||
// The second one will succeed.
|
||||
s.On("WatchTree", "path/"+defaultDiscoveryPath, 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", defaultDiscoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")},
|
||||
{Key: path.Join("path", defaultDiscoveryPath, "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 WatchTree 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", defaultDiscoveryPath, "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/"+defaultDiscoveryPath, mock.Anything).Return(mockCh, nil)
|
||||
close(mockCh)
|
||||
// Give it enough time to call WatchTree.
|
||||
time.Sleep(3)
|
||||
|
||||
// Stop and make sure it closes all channels.
|
||||
close(stopCh)
|
||||
assert.Nil(t, <-ch)
|
||||
assert.Nil(t, <-errCh)
|
||||
|
||||
s.AssertExpectations(t)
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package nodes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
d := &Discovery{}
|
||||
d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0, nil)
|
||||
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 TestInitializeWithPattern(t *testing.T) {
|
||||
d := &Discovery{}
|
||||
d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0, nil)
|
||||
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, nil)
|
||||
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) {
|
||||
d := &Discovery{}
|
||||
assert.Error(t, d.Register("0.0.0.0"))
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
)
|
||||
|
||||
const discoveryURL = "https://discovery.hub.docker.com/v1"
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/swarm/discovery"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -209,8 +209,9 @@ swarm is connected to the public internet. To create your swarm:
|
|||
|
||||
You can contribute a new discovery backend to Swarm. For information on how to
|
||||
do this, see <a
|
||||
href="https://github.com/docker/swarm/blob/master/discovery/README.md">our
|
||||
discovery README in the Docker Swarm repository</a>.
|
||||
href="https://github.com/docker/docker/tree/master/pkg/discovery">
|
||||
github.com/docker/docker/pkg/discovery</a>.
|
||||
|
||||
|
||||
## Docker Swarm documentation index
|
||||
|
||||
|
|
6
main.go
6
main.go
|
@ -1,9 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/docker/swarm/discovery/file"
|
||||
_ "github.com/docker/swarm/discovery/kv"
|
||||
_ "github.com/docker/swarm/discovery/nodes"
|
||||
_ "github.com/docker/docker/pkg/discovery/file"
|
||||
_ "github.com/docker/docker/pkg/discovery/kv"
|
||||
_ "github.com/docker/docker/pkg/discovery/nodes"
|
||||
_ "github.com/docker/swarm/discovery/token"
|
||||
|
||||
"github.com/docker/swarm/cli"
|
||||
|
|
Loading…
Reference in New Issue