uprev docker/docker, dbus to v4.0.0, boltdb to v1.2.0 to vendor dependencies required for build clean on Solaris
Signed-off-by: Amit Krishnan <krish.amit@gmail.com>
This commit is contained in:
parent
5108711b88
commit
f09dae40f7
223 changed files with 2083 additions and 43356 deletions
96
libnetwork/Godeps/Godeps.json
generated
96
libnetwork/Godeps/Godeps.json
generated
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"ImportPath": "github.com/docker/libnetwork",
|
||||
"GoVersion": "go1.4.2",
|
||||
"GoVersion": "go1.5",
|
||||
"GodepVersion": "v62",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
|
@ -20,6 +21,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/Microsoft/go-winio",
|
||||
"Comment": "v0.1.0",
|
||||
"Rev": "8f9387ea7efabb228a981b9c381142be7667967f"
|
||||
},
|
||||
{
|
||||
|
@ -41,8 +43,8 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/boltdb/bolt",
|
||||
"Comment": "v1.0-117-g0f053fa",
|
||||
"Rev": "0f053fabc06119583d61937a0a06ef0ba0f1b301"
|
||||
"Comment": "v1.2.0",
|
||||
"Rev": "c6ba97b89e0454fec9aa92e1d33a4e2c5fc1f631"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
|
@ -81,108 +83,108 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/opts",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/discovery",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/discovery/kv",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/homedir",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/ioutils",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/longpath",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/mflag",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/mount",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers/kernel",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/plugins",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/plugins/transport",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/proxy",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/random",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/reexec",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/signal",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/stringid",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/symlink",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/system",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term/windows",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/tlsconfig",
|
||||
"Comment": "v1.4.1-11287-geaf138a",
|
||||
"Rev": "eaf138af1fba339d13bc4cccd75e61e37603a51a"
|
||||
"Comment": "v1.4.1-11716-g24076ed",
|
||||
"Rev": "24076ed4d9c82d387029b8a65e21873db5676f6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/go-connections/sockets",
|
||||
|
@ -235,8 +237,8 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/godbus/dbus",
|
||||
"Comment": "v3",
|
||||
"Rev": "c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f"
|
||||
"Comment": "v4.0.0",
|
||||
"Rev": "5f6efc7ef2759c81b7ba876593971bfce311eab3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/proto",
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# Implements the TOML test suite interface
|
||||
|
||||
This is an implementation of the interface expected by
|
||||
[toml-test](https://github.com/BurntSushi/toml-test) for my
|
||||
[toml parser written in Go](https://github.com/BurntSushi/toml).
|
||||
In particular, it maps TOML data on `stdin` to a JSON format on `stdout`.
|
||||
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
|
||||
|
||||
Compatible with `toml-test` version
|
||||
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
// Command toml-test-decoder satisfies the toml-test interface for testing
|
||||
// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func usage() {
|
||||
log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
|
||||
flag.PrintDefaults()
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
var tmp interface{}
|
||||
if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil {
|
||||
log.Fatalf("Error decoding TOML: %s", err)
|
||||
}
|
||||
|
||||
typedTmp := translate(tmp)
|
||||
if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil {
|
||||
log.Fatalf("Error encoding JSON: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func translate(tomlData interface{}) interface{} {
|
||||
switch orig := tomlData.(type) {
|
||||
case map[string]interface{}:
|
||||
typed := make(map[string]interface{}, len(orig))
|
||||
for k, v := range orig {
|
||||
typed[k] = translate(v)
|
||||
}
|
||||
return typed
|
||||
case []map[string]interface{}:
|
||||
typed := make([]map[string]interface{}, len(orig))
|
||||
for i, v := range orig {
|
||||
typed[i] = translate(v).(map[string]interface{})
|
||||
}
|
||||
return typed
|
||||
case []interface{}:
|
||||
typed := make([]interface{}, len(orig))
|
||||
for i, v := range orig {
|
||||
typed[i] = translate(v)
|
||||
}
|
||||
|
||||
// We don't really need to tag arrays, but let's be future proof.
|
||||
// (If TOML ever supports tuples, we'll need this.)
|
||||
return tag("array", typed)
|
||||
case time.Time:
|
||||
return tag("datetime", orig.Format("2006-01-02T15:04:05Z"))
|
||||
case bool:
|
||||
return tag("bool", fmt.Sprintf("%v", orig))
|
||||
case int64:
|
||||
return tag("integer", fmt.Sprintf("%d", orig))
|
||||
case float64:
|
||||
return tag("float", fmt.Sprintf("%v", orig))
|
||||
case string:
|
||||
return tag("string", orig)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Unknown type: %T", tomlData))
|
||||
}
|
||||
|
||||
func tag(typeName string, data interface{}) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": typeName,
|
||||
"value": data,
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# Implements the TOML test suite interface for TOML encoders
|
||||
|
||||
This is an implementation of the interface expected by
|
||||
[toml-test](https://github.com/BurntSushi/toml-test) for the
|
||||
[TOML encoder](https://github.com/BurntSushi/toml).
|
||||
In particular, it maps JSON data on `stdin` to a TOML format on `stdout`.
|
||||
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
|
||||
|
||||
Compatible with `toml-test` version
|
||||
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
|
||||
|
131
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
generated
vendored
131
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
generated
vendored
|
@ -1,131 +0,0 @@
|
|||
// Command toml-test-encoder satisfies the toml-test interface for testing
|
||||
// TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func usage() {
|
||||
log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
|
||||
flag.PrintDefaults()
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
var tmp interface{}
|
||||
if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
|
||||
log.Fatalf("Error decoding JSON: %s", err)
|
||||
}
|
||||
|
||||
tomlData := translate(tmp)
|
||||
if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
|
||||
log.Fatalf("Error encoding TOML: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func translate(typedJson interface{}) interface{} {
|
||||
switch v := typedJson.(type) {
|
||||
case map[string]interface{}:
|
||||
if len(v) == 2 && in("type", v) && in("value", v) {
|
||||
return untag(v)
|
||||
}
|
||||
m := make(map[string]interface{}, len(v))
|
||||
for k, v2 := range v {
|
||||
m[k] = translate(v2)
|
||||
}
|
||||
return m
|
||||
case []interface{}:
|
||||
tabArray := make([]map[string]interface{}, len(v))
|
||||
for i := range v {
|
||||
if m, ok := translate(v[i]).(map[string]interface{}); ok {
|
||||
tabArray[i] = m
|
||||
} else {
|
||||
log.Fatalf("JSON arrays may only contain objects. This " +
|
||||
"corresponds to only tables being allowed in " +
|
||||
"TOML table arrays.")
|
||||
}
|
||||
}
|
||||
return tabArray
|
||||
}
|
||||
log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func untag(typed map[string]interface{}) interface{} {
|
||||
t := typed["type"].(string)
|
||||
v := typed["value"]
|
||||
switch t {
|
||||
case "string":
|
||||
return v.(string)
|
||||
case "integer":
|
||||
v := v.(string)
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not parse '%s' as integer: %s", v, err)
|
||||
}
|
||||
return n
|
||||
case "float":
|
||||
v := v.(string)
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not parse '%s' as float64: %s", v, err)
|
||||
}
|
||||
return f
|
||||
case "datetime":
|
||||
v := v.(string)
|
||||
t, err := time.Parse("2006-01-02T15:04:05Z", v)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
|
||||
}
|
||||
return t
|
||||
case "bool":
|
||||
v := v.(string)
|
||||
switch v {
|
||||
case "true":
|
||||
return true
|
||||
case "false":
|
||||
return false
|
||||
}
|
||||
log.Fatalf("Could not parse '%s' as a boolean.", v)
|
||||
case "array":
|
||||
v := v.([]interface{})
|
||||
array := make([]interface{}, len(v))
|
||||
for i := range v {
|
||||
if m, ok := v[i].(map[string]interface{}); ok {
|
||||
array[i] = untag(m)
|
||||
} else {
|
||||
log.Fatalf("Arrays may only contain other arrays or "+
|
||||
"primitive values, but found a '%T'.", m)
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
log.Fatalf("Unrecognized tag type '%s'.", t)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func in(key string, m map[string]interface{}) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
14
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/COPYING
generated
vendored
14
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/COPYING
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
22
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/README.md
generated
vendored
22
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/README.md
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
# TOML Validator
|
||||
|
||||
If Go is installed, it's simple to try it out:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml/cmd/tomlv
|
||||
tomlv some-toml-file.toml
|
||||
```
|
||||
|
||||
You can see the types of every key in a TOML file with:
|
||||
|
||||
```bash
|
||||
tomlv -types some-toml-file.toml
|
||||
```
|
||||
|
||||
At the moment, only one error message is reported at a time. Error messages
|
||||
include line numbers. No output means that the files given are valid TOML, or
|
||||
there is a bug in `tomlv`.
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.1.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.1.0.md)
|
||||
|
61
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/main.go
generated
vendored
61
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/cmd/tomlv/main.go
generated
vendored
|
@ -1,61 +0,0 @@
|
|||
// Command tomlv validates TOML documents and prints each key's type.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
var (
|
||||
flagTypes = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
|
||||
flag.BoolVar(&flagTypes, "types", flagTypes,
|
||||
"When set, the types of every defined key will be shown.")
|
||||
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func usage() {
|
||||
log.Printf("Usage: %s toml-file [ toml-file ... ]\n",
|
||||
path.Base(os.Args[0]))
|
||||
flag.PrintDefaults()
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if flag.NArg() < 1 {
|
||||
flag.Usage()
|
||||
}
|
||||
for _, f := range flag.Args() {
|
||||
var tmp interface{}
|
||||
md, err := toml.DecodeFile(f, &tmp)
|
||||
if err != nil {
|
||||
log.Fatalf("Error in '%s': %s", f, err)
|
||||
}
|
||||
if flagTypes {
|
||||
printTypes(md)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printTypes(md toml.MetaData) {
|
||||
tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
for _, key := range md.Keys() {
|
||||
fmt.Fprintf(tabw, "%s%s\t%s\n",
|
||||
strings.Repeat(" ", len(key)-1), key, md.Type(key...))
|
||||
}
|
||||
tabw.Flush()
|
||||
}
|
950
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/decode_test.go
generated
vendored
950
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/decode_test.go
generated
vendored
|
@ -1,950 +0,0 @@
|
|||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
}
|
||||
|
||||
func TestDecodeSimple(t *testing.T) {
|
||||
var testSimple = `
|
||||
age = 250
|
||||
andrew = "gallant"
|
||||
kait = "brady"
|
||||
now = 1987-07-05T05:45:00Z
|
||||
yesOrNo = true
|
||||
pi = 3.14
|
||||
colors = [
|
||||
["red", "green", "blue"],
|
||||
["cyan", "magenta", "yellow", "black"],
|
||||
]
|
||||
|
||||
[My.Cats]
|
||||
plato = "cat 1"
|
||||
cauchy = "cat 2"
|
||||
`
|
||||
|
||||
type cats struct {
|
||||
Plato string
|
||||
Cauchy string
|
||||
}
|
||||
type simple struct {
|
||||
Age int
|
||||
Colors [][]string
|
||||
Pi float64
|
||||
YesOrNo bool
|
||||
Now time.Time
|
||||
Andrew string
|
||||
Kait string
|
||||
My map[string]cats
|
||||
}
|
||||
|
||||
var val simple
|
||||
_, err := Decode(testSimple, &val)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
now, err := time.Parse("2006-01-02T15:04:05", "1987-07-05T05:45:00")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var answer = simple{
|
||||
Age: 250,
|
||||
Andrew: "gallant",
|
||||
Kait: "brady",
|
||||
Now: now,
|
||||
YesOrNo: true,
|
||||
Pi: 3.14,
|
||||
Colors: [][]string{
|
||||
{"red", "green", "blue"},
|
||||
{"cyan", "magenta", "yellow", "black"},
|
||||
},
|
||||
My: map[string]cats{
|
||||
"Cats": cats{Plato: "cat 1", Cauchy: "cat 2"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(val, answer) {
|
||||
t.Fatalf("Expected\n-----\n%#v\n-----\nbut got\n-----\n%#v\n",
|
||||
answer, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeEmbedded(t *testing.T) {
|
||||
type Dog struct{ Name string }
|
||||
type Age int
|
||||
|
||||
tests := map[string]struct {
|
||||
input string
|
||||
decodeInto interface{}
|
||||
wantDecoded interface{}
|
||||
}{
|
||||
"embedded struct": {
|
||||
input: `Name = "milton"`,
|
||||
decodeInto: &struct{ Dog }{},
|
||||
wantDecoded: &struct{ Dog }{Dog{"milton"}},
|
||||
},
|
||||
"embedded non-nil pointer to struct": {
|
||||
input: `Name = "milton"`,
|
||||
decodeInto: &struct{ *Dog }{},
|
||||
wantDecoded: &struct{ *Dog }{&Dog{"milton"}},
|
||||
},
|
||||
"embedded nil pointer to struct": {
|
||||
input: ``,
|
||||
decodeInto: &struct{ *Dog }{},
|
||||
wantDecoded: &struct{ *Dog }{nil},
|
||||
},
|
||||
"embedded int": {
|
||||
input: `Age = -5`,
|
||||
decodeInto: &struct{ Age }{},
|
||||
wantDecoded: &struct{ Age }{-5},
|
||||
},
|
||||
}
|
||||
|
||||
for label, test := range tests {
|
||||
_, err := Decode(test.input, test.decodeInto)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.wantDecoded, test.decodeInto) {
|
||||
t.Errorf("%s: want decoded == %+v, got %+v",
|
||||
label, test.wantDecoded, test.decodeInto)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableArrays(t *testing.T) {
|
||||
var tomlTableArrays = `
|
||||
[[albums]]
|
||||
name = "Born to Run"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Jungleland"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Meeting Across the River"
|
||||
|
||||
[[albums]]
|
||||
name = "Born in the USA"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Glory Days"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Dancing in the Dark"
|
||||
`
|
||||
|
||||
type Song struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
type Album struct {
|
||||
Name string
|
||||
Songs []Song
|
||||
}
|
||||
|
||||
type Music struct {
|
||||
Albums []Album
|
||||
}
|
||||
|
||||
expected := Music{[]Album{
|
||||
{"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}},
|
||||
{"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}},
|
||||
}}
|
||||
var got Music
|
||||
if _, err := Decode(tomlTableArrays, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, got) {
|
||||
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
// Case insensitive matching tests.
|
||||
// A bit more comprehensive than needed given the current implementation,
|
||||
// but implementations change.
|
||||
// Probably still missing demonstrations of some ugly corner cases regarding
|
||||
// case insensitive matching and multiple fields.
|
||||
func TestCase(t *testing.T) {
|
||||
var caseToml = `
|
||||
tOpString = "string"
|
||||
tOpInt = 1
|
||||
tOpFloat = 1.1
|
||||
tOpBool = true
|
||||
tOpdate = 2006-01-02T15:04:05Z
|
||||
tOparray = [ "array" ]
|
||||
Match = "i should be in Match only"
|
||||
MatcH = "i should be in MatcH only"
|
||||
once = "just once"
|
||||
[nEst.eD]
|
||||
nEstedString = "another string"
|
||||
`
|
||||
|
||||
type InsensitiveEd struct {
|
||||
NestedString string
|
||||
}
|
||||
|
||||
type InsensitiveNest struct {
|
||||
Ed InsensitiveEd
|
||||
}
|
||||
|
||||
type Insensitive struct {
|
||||
TopString string
|
||||
TopInt int
|
||||
TopFloat float64
|
||||
TopBool bool
|
||||
TopDate time.Time
|
||||
TopArray []string
|
||||
Match string
|
||||
MatcH string
|
||||
Once string
|
||||
OncE string
|
||||
Nest InsensitiveNest
|
||||
}
|
||||
|
||||
tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
expected := Insensitive{
|
||||
TopString: "string",
|
||||
TopInt: 1,
|
||||
TopFloat: 1.1,
|
||||
TopBool: true,
|
||||
TopDate: tme,
|
||||
TopArray: []string{"array"},
|
||||
MatcH: "i should be in MatcH only",
|
||||
Match: "i should be in Match only",
|
||||
Once: "just once",
|
||||
OncE: "",
|
||||
Nest: InsensitiveNest{
|
||||
Ed: InsensitiveEd{NestedString: "another string"},
|
||||
},
|
||||
}
|
||||
var got Insensitive
|
||||
if _, err := Decode(caseToml, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, got) {
|
||||
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointers(t *testing.T) {
|
||||
type Object struct {
|
||||
Type string
|
||||
Description string
|
||||
}
|
||||
|
||||
type Dict struct {
|
||||
NamedObject map[string]*Object
|
||||
BaseObject *Object
|
||||
Strptr *string
|
||||
Strptrs []*string
|
||||
}
|
||||
s1, s2, s3 := "blah", "abc", "def"
|
||||
expected := &Dict{
|
||||
Strptr: &s1,
|
||||
Strptrs: []*string{&s2, &s3},
|
||||
NamedObject: map[string]*Object{
|
||||
"foo": {"FOO", "fooooo!!!"},
|
||||
"bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"},
|
||||
},
|
||||
BaseObject: &Object{"BASE", "da base"},
|
||||
}
|
||||
|
||||
ex1 := `
|
||||
Strptr = "blah"
|
||||
Strptrs = ["abc", "def"]
|
||||
|
||||
[NamedObject.foo]
|
||||
Type = "FOO"
|
||||
Description = "fooooo!!!"
|
||||
|
||||
[NamedObject.bar]
|
||||
Type = "BAR"
|
||||
Description = "ba-ba-ba-ba-barrrr!!!"
|
||||
|
||||
[BaseObject]
|
||||
Type = "BASE"
|
||||
Description = "da base"
|
||||
`
|
||||
dict := new(Dict)
|
||||
_, err := Decode(ex1, dict)
|
||||
if err != nil {
|
||||
t.Errorf("Decode error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, dict) {
|
||||
t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict)
|
||||
}
|
||||
}
|
||||
|
||||
type sphere struct {
|
||||
Center [3]float64
|
||||
Radius float64
|
||||
}
|
||||
|
||||
func TestDecodeSimpleArray(t *testing.T) {
|
||||
var s1 sphere
|
||||
if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeArrayWrongSize(t *testing.T) {
|
||||
var s1 sphere
|
||||
if _, err := Decode(`center = [0.1, 2.3]`, &s1); err == nil {
|
||||
t.Fatal("Expected array type mismatch error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeLargeIntoSmallInt(t *testing.T) {
|
||||
type table struct {
|
||||
Value int8
|
||||
}
|
||||
var tab table
|
||||
if _, err := Decode(`value = 500`, &tab); err == nil {
|
||||
t.Fatal("Expected integer out-of-bounds error.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeSizedInts(t *testing.T) {
|
||||
type table struct {
|
||||
U8 uint8
|
||||
U16 uint16
|
||||
U32 uint32
|
||||
U64 uint64
|
||||
U uint
|
||||
I8 int8
|
||||
I16 int16
|
||||
I32 int32
|
||||
I64 int64
|
||||
I int
|
||||
}
|
||||
answer := table{1, 1, 1, 1, 1, -1, -1, -1, -1, -1}
|
||||
toml := `
|
||||
u8 = 1
|
||||
u16 = 1
|
||||
u32 = 1
|
||||
u64 = 1
|
||||
u = 1
|
||||
i8 = -1
|
||||
i16 = -1
|
||||
i32 = -1
|
||||
i64 = -1
|
||||
i = -1
|
||||
`
|
||||
var tab table
|
||||
if _, err := Decode(toml, &tab); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if answer != tab {
|
||||
t.Fatalf("Expected %#v but got %#v", answer, tab)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshaler(t *testing.T) {
|
||||
|
||||
var tomlBlob = `
|
||||
[dishes.hamboogie]
|
||||
name = "Hamboogie with fries"
|
||||
price = 10.99
|
||||
|
||||
[[dishes.hamboogie.ingredients]]
|
||||
name = "Bread Bun"
|
||||
|
||||
[[dishes.hamboogie.ingredients]]
|
||||
name = "Lettuce"
|
||||
|
||||
[[dishes.hamboogie.ingredients]]
|
||||
name = "Real Beef Patty"
|
||||
|
||||
[[dishes.hamboogie.ingredients]]
|
||||
name = "Tomato"
|
||||
|
||||
[dishes.eggsalad]
|
||||
name = "Egg Salad with rice"
|
||||
price = 3.99
|
||||
|
||||
[[dishes.eggsalad.ingredients]]
|
||||
name = "Egg"
|
||||
|
||||
[[dishes.eggsalad.ingredients]]
|
||||
name = "Mayo"
|
||||
|
||||
[[dishes.eggsalad.ingredients]]
|
||||
name = "Rice"
|
||||
`
|
||||
m := &menu{}
|
||||
if _, err := Decode(tomlBlob, m); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(m.Dishes) != 2 {
|
||||
t.Log("two dishes should be loaded with UnmarshalTOML()")
|
||||
t.Errorf("expected %d but got %d", 2, len(m.Dishes))
|
||||
}
|
||||
|
||||
eggSalad := m.Dishes["eggsalad"]
|
||||
if _, ok := interface{}(eggSalad).(dish); !ok {
|
||||
t.Errorf("expected a dish")
|
||||
}
|
||||
|
||||
if eggSalad.Name != "Egg Salad with rice" {
|
||||
t.Errorf("expected the dish to be named 'Egg Salad with rice'")
|
||||
}
|
||||
|
||||
if len(eggSalad.Ingredients) != 3 {
|
||||
t.Log("dish should be loaded with UnmarshalTOML()")
|
||||
t.Errorf("expected %d but got %d", 3, len(eggSalad.Ingredients))
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, i := range eggSalad.Ingredients {
|
||||
if i.Name == "Rice" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("Rice was not loaded in UnmarshalTOML()")
|
||||
}
|
||||
|
||||
// test on a value - must be passed as *
|
||||
o := menu{}
|
||||
if _, err := Decode(tomlBlob, &o); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type menu struct {
|
||||
Dishes map[string]dish
|
||||
}
|
||||
|
||||
func (m *menu) UnmarshalTOML(p interface{}) error {
|
||||
m.Dishes = make(map[string]dish)
|
||||
data, _ := p.(map[string]interface{})
|
||||
dishes := data["dishes"].(map[string]interface{})
|
||||
for n, v := range dishes {
|
||||
if d, ok := v.(map[string]interface{}); ok {
|
||||
nd := dish{}
|
||||
nd.UnmarshalTOML(d)
|
||||
m.Dishes[n] = nd
|
||||
} else {
|
||||
return fmt.Errorf("not a dish")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type dish struct {
|
||||
Name string
|
||||
Price float32
|
||||
Ingredients []ingredient
|
||||
}
|
||||
|
||||
func (d *dish) UnmarshalTOML(p interface{}) error {
|
||||
data, _ := p.(map[string]interface{})
|
||||
d.Name, _ = data["name"].(string)
|
||||
d.Price, _ = data["price"].(float32)
|
||||
ingredients, _ := data["ingredients"].([]map[string]interface{})
|
||||
for _, e := range ingredients {
|
||||
n, _ := interface{}(e).(map[string]interface{})
|
||||
name, _ := n["name"].(string)
|
||||
i := ingredient{name}
|
||||
d.Ingredients = append(d.Ingredients, i)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ingredient struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func ExampleMetaData_PrimitiveDecode() {
|
||||
var md MetaData
|
||||
var err error
|
||||
|
||||
var tomlBlob = `
|
||||
ranking = ["Springsteen", "J Geils"]
|
||||
|
||||
[bands.Springsteen]
|
||||
started = 1973
|
||||
albums = ["Greetings", "WIESS", "Born to Run", "Darkness"]
|
||||
|
||||
[bands."J Geils"]
|
||||
started = 1970
|
||||
albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"]
|
||||
`
|
||||
|
||||
type band struct {
|
||||
Started int
|
||||
Albums []string
|
||||
}
|
||||
type classics struct {
|
||||
Ranking []string
|
||||
Bands map[string]Primitive
|
||||
}
|
||||
|
||||
// Do the initial decode. Reflection is delayed on Primitive values.
|
||||
var music classics
|
||||
if md, err = Decode(tomlBlob, &music); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// MetaData still includes information on Primitive values.
|
||||
fmt.Printf("Is `bands.Springsteen` defined? %v\n",
|
||||
md.IsDefined("bands", "Springsteen"))
|
||||
|
||||
// Decode primitive data into Go values.
|
||||
for _, artist := range music.Ranking {
|
||||
// A band is a primitive value, so we need to decode it to get a
|
||||
// real `band` value.
|
||||
primValue := music.Bands[artist]
|
||||
|
||||
var aBand band
|
||||
if err = md.PrimitiveDecode(primValue, &aBand); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%s started in %d.\n", artist, aBand.Started)
|
||||
}
|
||||
// Check to see if there were any fields left undecoded.
|
||||
// Note that this won't be empty before decoding the Primitive value!
|
||||
fmt.Printf("Undecoded: %q\n", md.Undecoded())
|
||||
|
||||
// Output:
|
||||
// Is `bands.Springsteen` defined? true
|
||||
// Springsteen started in 1973.
|
||||
// J Geils started in 1970.
|
||||
// Undecoded: []
|
||||
}
|
||||
|
||||
func ExampleDecode() {
|
||||
var tomlBlob = `
|
||||
# Some comments.
|
||||
[alpha]
|
||||
ip = "10.0.0.1"
|
||||
|
||||
[alpha.config]
|
||||
Ports = [ 8001, 8002 ]
|
||||
Location = "Toronto"
|
||||
Created = 1987-07-05T05:45:00Z
|
||||
|
||||
[beta]
|
||||
ip = "10.0.0.2"
|
||||
|
||||
[beta.config]
|
||||
Ports = [ 9001, 9002 ]
|
||||
Location = "New Jersey"
|
||||
Created = 1887-01-05T05:55:00Z
|
||||
`
|
||||
|
||||
type serverConfig struct {
|
||||
Ports []int
|
||||
Location string
|
||||
Created time.Time
|
||||
}
|
||||
|
||||
type server struct {
|
||||
IP string `toml:"ip"`
|
||||
Config serverConfig `toml:"config"`
|
||||
}
|
||||
|
||||
type servers map[string]server
|
||||
|
||||
var config servers
|
||||
if _, err := Decode(tomlBlob, &config); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, name := range []string{"alpha", "beta"} {
|
||||
s := config[name]
|
||||
fmt.Printf("Server: %s (ip: %s) in %s created on %s\n",
|
||||
name, s.IP, s.Config.Location,
|
||||
s.Config.Created.Format("2006-01-02"))
|
||||
fmt.Printf("Ports: %v\n", s.Config.Ports)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05
|
||||
// Ports: [8001 8002]
|
||||
// Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05
|
||||
// Ports: [9001 9002]
|
||||
}
|
||||
|
||||
type duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *duration) UnmarshalText(text []byte) error {
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(string(text))
|
||||
return err
|
||||
}
|
||||
|
||||
// Example Unmarshaler shows how to decode TOML strings into your own
|
||||
// custom data type.
|
||||
func Example_unmarshaler() {
|
||||
blob := `
|
||||
[[song]]
|
||||
name = "Thunder Road"
|
||||
duration = "4m49s"
|
||||
|
||||
[[song]]
|
||||
name = "Stairway to Heaven"
|
||||
duration = "8m03s"
|
||||
`
|
||||
type song struct {
|
||||
Name string
|
||||
Duration duration
|
||||
}
|
||||
type songs struct {
|
||||
Song []song
|
||||
}
|
||||
var favorites songs
|
||||
if _, err := Decode(blob, &favorites); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Code to implement the TextUnmarshaler interface for `duration`:
|
||||
//
|
||||
// type duration struct {
|
||||
// time.Duration
|
||||
// }
|
||||
//
|
||||
// func (d *duration) UnmarshalText(text []byte) error {
|
||||
// var err error
|
||||
// d.Duration, err = time.ParseDuration(string(text))
|
||||
// return err
|
||||
// }
|
||||
|
||||
for _, s := range favorites.Song {
|
||||
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
|
||||
}
|
||||
// Output:
|
||||
// Thunder Road (4m49s)
|
||||
// Stairway to Heaven (8m3s)
|
||||
}
|
||||
|
||||
// Example StrictDecoding shows how to detect whether there are keys in the
|
||||
// TOML document that weren't decoded into the value given. This is useful
|
||||
// for returning an error to the user if they've included extraneous fields
|
||||
// in their configuration.
|
||||
func Example_strictDecoding() {
|
||||
var blob = `
|
||||
key1 = "value1"
|
||||
key2 = "value2"
|
||||
key3 = "value3"
|
||||
`
|
||||
type config struct {
|
||||
Key1 string
|
||||
Key3 string
|
||||
}
|
||||
|
||||
var conf config
|
||||
md, err := Decode(blob, &conf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Undecoded keys: %q\n", md.Undecoded())
|
||||
// Output:
|
||||
// Undecoded keys: ["key2"]
|
||||
}
|
||||
|
||||
// Example UnmarshalTOML shows how to implement a struct type that knows how to
|
||||
// unmarshal itself. The struct must take full responsibility for mapping the
|
||||
// values passed into the struct. The method may be used with interfaces in a
|
||||
// struct in cases where the actual type is not known until the data is
|
||||
// examined.
|
||||
func Example_unmarshalTOML() {
|
||||
|
||||
var blob = `
|
||||
[[parts]]
|
||||
type = "valve"
|
||||
id = "valve-1"
|
||||
size = 1.2
|
||||
rating = 4
|
||||
|
||||
[[parts]]
|
||||
type = "valve"
|
||||
id = "valve-2"
|
||||
size = 2.1
|
||||
rating = 5
|
||||
|
||||
[[parts]]
|
||||
type = "pipe"
|
||||
id = "pipe-1"
|
||||
length = 2.1
|
||||
diameter = 12
|
||||
|
||||
[[parts]]
|
||||
type = "cable"
|
||||
id = "cable-1"
|
||||
length = 12
|
||||
rating = 3.1
|
||||
`
|
||||
o := &order{}
|
||||
err := Unmarshal([]byte(blob), o)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(len(o.parts))
|
||||
|
||||
for _, part := range o.parts {
|
||||
fmt.Println(part.Name())
|
||||
}
|
||||
|
||||
// Code to implement UmarshalJSON.
|
||||
|
||||
// type order struct {
|
||||
// // NOTE `order.parts` is a private slice of type `part` which is an
|
||||
// // interface and may only be loaded from toml using the
|
||||
// // UnmarshalTOML() method of the Umarshaler interface.
|
||||
// parts parts
|
||||
// }
|
||||
|
||||
// func (o *order) UnmarshalTOML(data interface{}) error {
|
||||
|
||||
// // NOTE the example below contains detailed type casting to show how
|
||||
// // the 'data' is retrieved. In operational use, a type cast wrapper
|
||||
// // may be prefered e.g.
|
||||
// //
|
||||
// // func AsMap(v interface{}) (map[string]interface{}, error) {
|
||||
// // return v.(map[string]interface{})
|
||||
// // }
|
||||
// //
|
||||
// // resulting in:
|
||||
// // d, _ := AsMap(data)
|
||||
// //
|
||||
|
||||
// d, _ := data.(map[string]interface{})
|
||||
// parts, _ := d["parts"].([]map[string]interface{})
|
||||
|
||||
// for _, p := range parts {
|
||||
|
||||
// typ, _ := p["type"].(string)
|
||||
// id, _ := p["id"].(string)
|
||||
|
||||
// // detect the type of part and handle each case
|
||||
// switch p["type"] {
|
||||
// case "valve":
|
||||
|
||||
// size := float32(p["size"].(float64))
|
||||
// rating := int(p["rating"].(int64))
|
||||
|
||||
// valve := &valve{
|
||||
// Type: typ,
|
||||
// ID: id,
|
||||
// Size: size,
|
||||
// Rating: rating,
|
||||
// }
|
||||
|
||||
// o.parts = append(o.parts, valve)
|
||||
|
||||
// case "pipe":
|
||||
|
||||
// length := float32(p["length"].(float64))
|
||||
// diameter := int(p["diameter"].(int64))
|
||||
|
||||
// pipe := &pipe{
|
||||
// Type: typ,
|
||||
// ID: id,
|
||||
// Length: length,
|
||||
// Diameter: diameter,
|
||||
// }
|
||||
|
||||
// o.parts = append(o.parts, pipe)
|
||||
|
||||
// case "cable":
|
||||
|
||||
// length := int(p["length"].(int64))
|
||||
// rating := float32(p["rating"].(float64))
|
||||
|
||||
// cable := &cable{
|
||||
// Type: typ,
|
||||
// ID: id,
|
||||
// Length: length,
|
||||
// Rating: rating,
|
||||
// }
|
||||
|
||||
// o.parts = append(o.parts, cable)
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// type parts []part
|
||||
|
||||
// type part interface {
|
||||
// Name() string
|
||||
// }
|
||||
|
||||
// type valve struct {
|
||||
// Type string
|
||||
// ID string
|
||||
// Size float32
|
||||
// Rating int
|
||||
// }
|
||||
|
||||
// func (v *valve) Name() string {
|
||||
// return fmt.Sprintf("VALVE: %s", v.ID)
|
||||
// }
|
||||
|
||||
// type pipe struct {
|
||||
// Type string
|
||||
// ID string
|
||||
// Length float32
|
||||
// Diameter int
|
||||
// }
|
||||
|
||||
// func (p *pipe) Name() string {
|
||||
// return fmt.Sprintf("PIPE: %s", p.ID)
|
||||
// }
|
||||
|
||||
// type cable struct {
|
||||
// Type string
|
||||
// ID string
|
||||
// Length int
|
||||
// Rating float32
|
||||
// }
|
||||
|
||||
// func (c *cable) Name() string {
|
||||
// return fmt.Sprintf("CABLE: %s", c.ID)
|
||||
// }
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// VALVE: valve-1
|
||||
// VALVE: valve-2
|
||||
// PIPE: pipe-1
|
||||
// CABLE: cable-1
|
||||
|
||||
}
|
||||
|
||||
type order struct {
|
||||
// NOTE `order.parts` is a private slice of type `part` which is an
|
||||
// interface and may only be loaded from toml using the UnmarshalTOML()
|
||||
// method of the Umarshaler interface.
|
||||
parts parts
|
||||
}
|
||||
|
||||
func (o *order) UnmarshalTOML(data interface{}) error {
|
||||
|
||||
// NOTE the example below contains detailed type casting to show how
|
||||
// the 'data' is retrieved. In operational use, a type cast wrapper
|
||||
// may be prefered e.g.
|
||||
//
|
||||
// func AsMap(v interface{}) (map[string]interface{}, error) {
|
||||
// return v.(map[string]interface{})
|
||||
// }
|
||||
//
|
||||
// resulting in:
|
||||
// d, _ := AsMap(data)
|
||||
//
|
||||
|
||||
d, _ := data.(map[string]interface{})
|
||||
parts, _ := d["parts"].([]map[string]interface{})
|
||||
|
||||
for _, p := range parts {
|
||||
|
||||
typ, _ := p["type"].(string)
|
||||
id, _ := p["id"].(string)
|
||||
|
||||
// detect the type of part and handle each case
|
||||
switch p["type"] {
|
||||
case "valve":
|
||||
|
||||
size := float32(p["size"].(float64))
|
||||
rating := int(p["rating"].(int64))
|
||||
|
||||
valve := &valve{
|
||||
Type: typ,
|
||||
ID: id,
|
||||
Size: size,
|
||||
Rating: rating,
|
||||
}
|
||||
|
||||
o.parts = append(o.parts, valve)
|
||||
|
||||
case "pipe":
|
||||
|
||||
length := float32(p["length"].(float64))
|
||||
diameter := int(p["diameter"].(int64))
|
||||
|
||||
pipe := &pipe{
|
||||
Type: typ,
|
||||
ID: id,
|
||||
Length: length,
|
||||
Diameter: diameter,
|
||||
}
|
||||
|
||||
o.parts = append(o.parts, pipe)
|
||||
|
||||
case "cable":
|
||||
|
||||
length := int(p["length"].(int64))
|
||||
rating := float32(p["rating"].(float64))
|
||||
|
||||
cable := &cable{
|
||||
Type: typ,
|
||||
ID: id,
|
||||
Length: length,
|
||||
Rating: rating,
|
||||
}
|
||||
|
||||
o.parts = append(o.parts, cable)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type parts []part
|
||||
|
||||
type part interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
type valve struct {
|
||||
Type string
|
||||
ID string
|
||||
Size float32
|
||||
Rating int
|
||||
}
|
||||
|
||||
func (v *valve) Name() string {
|
||||
return fmt.Sprintf("VALVE: %s", v.ID)
|
||||
}
|
||||
|
||||
type pipe struct {
|
||||
Type string
|
||||
ID string
|
||||
Length float32
|
||||
Diameter int
|
||||
}
|
||||
|
||||
func (p *pipe) Name() string {
|
||||
return fmt.Sprintf("PIPE: %s", p.ID)
|
||||
}
|
||||
|
||||
type cable struct {
|
||||
Type string
|
||||
ID string
|
||||
Length int
|
||||
Rating float32
|
||||
}
|
||||
|
||||
func (c *cable) Name() string {
|
||||
return fmt.Sprintf("CABLE: %s", c.ID)
|
||||
}
|
506
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/encode_test.go
generated
vendored
506
libnetwork/Godeps/_workspace/src/github.com/BurntSushi/toml/encode_test.go
generated
vendored
|
@ -1,506 +0,0 @@
|
|||
package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestEncodeRoundTrip(t *testing.T) {
|
||||
type Config struct {
|
||||
Age int
|
||||
Cats []string
|
||||
Pi float64
|
||||
Perfection []int
|
||||
DOB time.Time
|
||||
Ipaddress net.IP
|
||||
}
|
||||
|
||||
var inputs = Config{
|
||||
13,
|
||||
[]string{"one", "two", "three"},
|
||||
3.145,
|
||||
[]int{11, 2, 3, 4},
|
||||
time.Now(),
|
||||
net.ParseIP("192.168.59.254"),
|
||||
}
|
||||
|
||||
var firstBuffer bytes.Buffer
|
||||
e := NewEncoder(&firstBuffer)
|
||||
err := e.Encode(inputs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var outputs Config
|
||||
if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
|
||||
log.Printf("Could not decode:\n-----\n%s\n-----\n",
|
||||
firstBuffer.String())
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// could test each value individually, but I'm lazy
|
||||
var secondBuffer bytes.Buffer
|
||||
e2 := NewEncoder(&secondBuffer)
|
||||
err = e2.Encode(outputs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if firstBuffer.String() != secondBuffer.String() {
|
||||
t.Error(
|
||||
firstBuffer.String(),
|
||||
"\n\n is not identical to\n\n",
|
||||
secondBuffer.String())
|
||||
}
|
||||
}
|
||||
|
||||
// XXX(burntsushi)
|
||||
// I think these tests probably should be removed. They are good, but they
|
||||
// ought to be obsolete by toml-test.
|
||||
func TestEncode(t *testing.T) {
|
||||
type Embedded struct {
|
||||
Int int `toml:"_int"`
|
||||
}
|
||||
type NonStruct int
|
||||
|
||||
date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
|
||||
dateStr := "2014-05-11T19:30:40Z"
|
||||
|
||||
tests := map[string]struct {
|
||||
input interface{}
|
||||
wantOutput string
|
||||
wantError error
|
||||
}{
|
||||
"bool field": {
|
||||
input: struct {
|
||||
BoolTrue bool
|
||||
BoolFalse bool
|
||||
}{true, false},
|
||||
wantOutput: "BoolTrue = true\nBoolFalse = false\n",
|
||||
},
|
||||
"int fields": {
|
||||
input: struct {
|
||||
Int int
|
||||
Int8 int8
|
||||
Int16 int16
|
||||
Int32 int32
|
||||
Int64 int64
|
||||
}{1, 2, 3, 4, 5},
|
||||
wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
|
||||
},
|
||||
"uint fields": {
|
||||
input: struct {
|
||||
Uint uint
|
||||
Uint8 uint8
|
||||
Uint16 uint16
|
||||
Uint32 uint32
|
||||
Uint64 uint64
|
||||
}{1, 2, 3, 4, 5},
|
||||
wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
|
||||
"\nUint64 = 5\n",
|
||||
},
|
||||
"float fields": {
|
||||
input: struct {
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
}{1.5, 2.5},
|
||||
wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
|
||||
},
|
||||
"string field": {
|
||||
input: struct{ String string }{"foo"},
|
||||
wantOutput: "String = \"foo\"\n",
|
||||
},
|
||||
"string field and unexported field": {
|
||||
input: struct {
|
||||
String string
|
||||
unexported int
|
||||
}{"foo", 0},
|
||||
wantOutput: "String = \"foo\"\n",
|
||||
},
|
||||
"datetime field in UTC": {
|
||||
input: struct{ Date time.Time }{date},
|
||||
wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
|
||||
},
|
||||
"datetime field as primitive": {
|
||||
// Using a map here to fail if isStructOrMap() returns true for
|
||||
// time.Time.
|
||||
input: map[string]interface{}{
|
||||
"Date": date,
|
||||
"Int": 1,
|
||||
},
|
||||
wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
|
||||
},
|
||||
"array fields": {
|
||||
input: struct {
|
||||
IntArray0 [0]int
|
||||
IntArray3 [3]int
|
||||
}{[0]int{}, [3]int{1, 2, 3}},
|
||||
wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
|
||||
},
|
||||
"slice fields": {
|
||||
input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
|
||||
nil, []int{}, []int{1, 2, 3},
|
||||
},
|
||||
wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
|
||||
},
|
||||
"datetime slices": {
|
||||
input: struct{ DatetimeSlice []time.Time }{
|
||||
[]time.Time{date, date},
|
||||
},
|
||||
wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
|
||||
dateStr, dateStr),
|
||||
},
|
||||
"nested arrays and slices": {
|
||||
input: struct {
|
||||
SliceOfArrays [][2]int
|
||||
ArrayOfSlices [2][]int
|
||||
SliceOfArraysOfSlices [][2][]int
|
||||
ArrayOfSlicesOfArrays [2][][2]int
|
||||
SliceOfMixedArrays [][2]interface{}
|
||||
ArrayOfMixedSlices [2][]interface{}
|
||||
}{
|
||||
[][2]int{{1, 2}, {3, 4}},
|
||||
[2][]int{{1, 2}, {3, 4}},
|
||||
[][2][]int{
|
||||
{
|
||||
{1, 2}, {3, 4},
|
||||
},
|
||||
{
|
||||
{5, 6}, {7, 8},
|
||||
},
|
||||
},
|
||||
[2][][2]int{
|
||||
{
|
||||
{1, 2}, {3, 4},
|
||||
},
|
||||
{
|
||||
{5, 6}, {7, 8},
|
||||
},
|
||||
},
|
||||
[][2]interface{}{
|
||||
{1, 2}, {"a", "b"},
|
||||
},
|
||||
[2][]interface{}{
|
||||
{1, 2}, {"a", "b"},
|
||||
},
|
||||
},
|
||||
wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
|
||||
ArrayOfSlices = [[1, 2], [3, 4]]
|
||||
SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
SliceOfMixedArrays = [[1, 2], ["a", "b"]]
|
||||
ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
|
||||
`,
|
||||
},
|
||||
"empty slice": {
|
||||
input: struct{ Empty []interface{} }{[]interface{}{}},
|
||||
wantOutput: "Empty = []\n",
|
||||
},
|
||||
"(error) slice with element type mismatch (string and integer)": {
|
||||
input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
|
||||
wantError: errArrayMixedElementTypes,
|
||||
},
|
||||
"(error) slice with element type mismatch (integer and float)": {
|
||||
input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
|
||||
wantError: errArrayMixedElementTypes,
|
||||
},
|
||||
"slice with elems of differing Go types, same TOML types": {
|
||||
input: struct {
|
||||
MixedInts []interface{}
|
||||
MixedFloats []interface{}
|
||||
}{
|
||||
[]interface{}{
|
||||
int(1), int8(2), int16(3), int32(4), int64(5),
|
||||
uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
|
||||
},
|
||||
[]interface{}{float32(1.5), float64(2.5)},
|
||||
},
|
||||
wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
|
||||
"MixedFloats = [1.5, 2.5]\n",
|
||||
},
|
||||
"(error) slice w/ element type mismatch (one is nested array)": {
|
||||
input: struct{ Mixed []interface{} }{
|
||||
[]interface{}{1, []interface{}{2}},
|
||||
},
|
||||
wantError: errArrayMixedElementTypes,
|
||||
},
|
||||
"(error) slice with 1 nil element": {
|
||||
input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
|
||||
wantError: errArrayNilElement,
|
||||
},
|
||||
"(error) slice with 1 nil element (and other non-nil elements)": {
|
||||
input: struct{ NilElement []interface{} }{
|
||||
[]interface{}{1, nil},
|
||||
},
|
||||
wantError: errArrayNilElement,
|
||||
},
|
||||
"simple map": {
|
||||
input: map[string]int{"a": 1, "b": 2},
|
||||
wantOutput: "a = 1\nb = 2\n",
|
||||
},
|
||||
"map with interface{} value type": {
|
||||
input: map[string]interface{}{"a": 1, "b": "c"},
|
||||
wantOutput: "a = 1\nb = \"c\"\n",
|
||||
},
|
||||
"map with interface{} value type, some of which are structs": {
|
||||
input: map[string]interface{}{
|
||||
"a": struct{ Int int }{2},
|
||||
"b": 1,
|
||||
},
|
||||
wantOutput: "b = 1\n\n[a]\n Int = 2\n",
|
||||
},
|
||||
"nested map": {
|
||||
input: map[string]map[string]int{
|
||||
"a": {"b": 1},
|
||||
"c": {"d": 2},
|
||||
},
|
||||
wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
|
||||
},
|
||||
"nested struct": {
|
||||
input: struct{ Struct struct{ Int int } }{
|
||||
struct{ Int int }{1},
|
||||
},
|
||||
wantOutput: "[Struct]\n Int = 1\n",
|
||||
},
|
||||
"nested struct and non-struct field": {
|
||||
input: struct {
|
||||
Struct struct{ Int int }
|
||||
Bool bool
|
||||
}{struct{ Int int }{1}, true},
|
||||
wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
|
||||
},
|
||||
"2 nested structs": {
|
||||
input: struct{ Struct1, Struct2 struct{ Int int } }{
|
||||
struct{ Int int }{1}, struct{ Int int }{2},
|
||||
},
|
||||
wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
|
||||
},
|
||||
"deeply nested structs": {
|
||||
input: struct {
|
||||
Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
|
||||
}{
|
||||
struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
|
||||
struct{ Struct3 *struct{ Int int } }{nil},
|
||||
},
|
||||
wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
|
||||
"\n\n[Struct2]\n",
|
||||
},
|
||||
"nested struct with nil struct elem": {
|
||||
input: struct {
|
||||
Struct struct{ Inner *struct{ Int int } }
|
||||
}{
|
||||
struct{ Inner *struct{ Int int } }{nil},
|
||||
},
|
||||
wantOutput: "[Struct]\n",
|
||||
},
|
||||
"nested struct with no fields": {
|
||||
input: struct {
|
||||
Struct struct{ Inner struct{} }
|
||||
}{
|
||||
struct{ Inner struct{} }{struct{}{}},
|
||||
},
|
||||
wantOutput: "[Struct]\n [Struct.Inner]\n",
|
||||
},
|
||||
"struct with tags": {
|
||||
input: struct {
|
||||
Struct struct {
|
||||
Int int `toml:"_int"`
|
||||
} `toml:"_struct"`
|
||||
Bool bool `toml:"_bool"`
|
||||
}{
|
||||
struct {
|
||||
Int int `toml:"_int"`
|
||||
}{1}, true,
|
||||
},
|
||||
wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
|
||||
},
|
||||
"embedded struct": {
|
||||
input: struct{ Embedded }{Embedded{1}},
|
||||
wantOutput: "_int = 1\n",
|
||||
},
|
||||
"embedded *struct": {
|
||||
input: struct{ *Embedded }{&Embedded{1}},
|
||||
wantOutput: "_int = 1\n",
|
||||
},
|
||||
"nested embedded struct": {
|
||||
input: struct {
|
||||
Struct struct{ Embedded } `toml:"_struct"`
|
||||
}{struct{ Embedded }{Embedded{1}}},
|
||||
wantOutput: "[_struct]\n _int = 1\n",
|
||||
},
|
||||
"nested embedded *struct": {
|
||||
input: struct {
|
||||
Struct struct{ *Embedded } `toml:"_struct"`
|
||||
}{struct{ *Embedded }{&Embedded{1}}},
|
||||
wantOutput: "[_struct]\n _int = 1\n",
|
||||
},
|
||||
"array of tables": {
|
||||
input: struct {
|
||||
Structs []*struct{ Int int } `toml:"struct"`
|
||||
}{
|
||||
[]*struct{ Int int }{{1}, {3}},
|
||||
},
|
||||
wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
|
||||
},
|
||||
"array of tables order": {
|
||||
input: map[string]interface{}{
|
||||
"map": map[string]interface{}{
|
||||
"zero": 5,
|
||||
"arr": []map[string]int{
|
||||
map[string]int{
|
||||
"friend": 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
|
||||
},
|
||||
"(error) top-level slice": {
|
||||
input: []struct{ Int int }{{1}, {2}, {3}},
|
||||
wantError: errNoKey,
|
||||
},
|
||||
"(error) slice of slice": {
|
||||
input: struct {
|
||||
Slices [][]struct{ Int int }
|
||||
}{
|
||||
[][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
|
||||
},
|
||||
wantError: errArrayNoTable,
|
||||
},
|
||||
"(error) map no string key": {
|
||||
input: map[int]string{1: ""},
|
||||
wantError: errNonString,
|
||||
},
|
||||
"(error) anonymous non-struct": {
|
||||
input: struct{ NonStruct }{5},
|
||||
wantError: errAnonNonStruct,
|
||||
},
|
||||
"(error) empty key name": {
|
||||
input: map[string]int{"": 1},
|
||||
wantError: errAnything,
|
||||
},
|
||||
"(error) empty map name": {
|
||||
input: map[string]interface{}{
|
||||
"": map[string]int{"v": 1},
|
||||
},
|
||||
wantError: errAnything,
|
||||
},
|
||||
}
|
||||
for label, test := range tests {
|
||||
encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeNestedTableArrays(t *testing.T) {
|
||||
type song struct {
|
||||
Name string `toml:"name"`
|
||||
}
|
||||
type album struct {
|
||||
Name string `toml:"name"`
|
||||
Songs []song `toml:"songs"`
|
||||
}
|
||||
type springsteen struct {
|
||||
Albums []album `toml:"albums"`
|
||||
}
|
||||
value := springsteen{
|
||||
[]album{
|
||||
{"Born to Run",
|
||||
[]song{{"Jungleland"}, {"Meeting Across the River"}}},
|
||||
{"Born in the USA",
|
||||
[]song{{"Glory Days"}, {"Dancing in the Dark"}}},
|
||||
},
|
||||
}
|
||||
expected := `[[albums]]
|
||||
name = "Born to Run"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Jungleland"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Meeting Across the River"
|
||||
|
||||
[[albums]]
|
||||
name = "Born in the USA"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Glory Days"
|
||||
|
||||
[[albums.songs]]
|
||||
name = "Dancing in the Dark"
|
||||
`
|
||||
encodeExpected(t, "nested table arrays", value, expected, nil)
|
||||
}
|
||||
|
||||
func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
|
||||
type Alpha struct {
|
||||
V int
|
||||
}
|
||||
type Beta struct {
|
||||
V int
|
||||
}
|
||||
type Conf struct {
|
||||
V int
|
||||
A Alpha
|
||||
B []Beta
|
||||
}
|
||||
|
||||
val := Conf{
|
||||
V: 1,
|
||||
A: Alpha{2},
|
||||
B: []Beta{{3}},
|
||||
}
|
||||
expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
|
||||
encodeExpected(t, "array hash with normal hash order", val, expected, nil)
|
||||
}
|
||||
|
||||
func encodeExpected(
|
||||
t *testing.T, label string, val interface{}, wantStr string, wantErr error,
|
||||
) {
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
err := enc.Encode(val)
|
||||
if err != wantErr {
|
||||
if wantErr != nil {
|
||||
if wantErr == errAnything && err != nil {
|
||||
return
|
||||
}
|
||||
t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
|
||||
} else {
|
||||
t.Errorf("%s: Encode failed: %s", label, err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if got := buf.String(); wantStr != got {
|
||||
t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
|
||||
label, wantStr, got)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEncoder_Encode() {
|
||||
date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
|
||||
var config = map[string]interface{}{
|
||||
"date": date,
|
||||
"counts": []int{1, 1, 2, 3, 5, 8},
|
||||
"hash": map[string]string{
|
||||
"key1": "val1",
|
||||
"key2": "val2",
|
||||
},
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
if err := NewEncoder(buf).Encode(config); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(buf.String())
|
||||
|
||||
// Output:
|
||||
// counts = [1, 1, 2, 3, 5, 8]
|
||||
// date = 2010-03-14T18:00:00Z
|
||||
//
|
||||
// [hash]
|
||||
// key1 = "val1"
|
||||
// key2 = "val2"
|
||||
}
|
255
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup_test.go
generated
vendored
255
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/backup_test.go
generated
vendored
|
@ -1,255 +0,0 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testFileName string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
f, err := ioutil.TempFile("", "tmp")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testFileName = f.Name()
|
||||
f.Close()
|
||||
defer os.Remove(testFileName)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func makeTestFile(makeADS bool) error {
|
||||
os.Remove(testFileName)
|
||||
f, err := os.Create(testFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write([]byte("testing 1 2 3\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if makeADS {
|
||||
a, err := os.Create(testFileName + ":ads.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
_, err = a.Write([]byte("alternate data stream\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBackupRead(t *testing.T) {
|
||||
err := makeTestFile(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Open(testFileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewBackupFileReader(f, false)
|
||||
defer r.Close()
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(b) == 0 {
|
||||
t.Fatal("no data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackupStreamRead(t *testing.T) {
|
||||
err := makeTestFile(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Open(testFileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewBackupFileReader(f, false)
|
||||
defer r.Close()
|
||||
|
||||
br := NewBackupStreamReader(r)
|
||||
gotData := false
|
||||
gotAltData := false
|
||||
for {
|
||||
hdr, err := br.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
switch hdr.Id {
|
||||
case BackupData:
|
||||
if gotData {
|
||||
t.Fatal("duplicate data")
|
||||
}
|
||||
if hdr.Name != "" {
|
||||
t.Fatalf("unexpected name %s", hdr.Name)
|
||||
}
|
||||
b, err := ioutil.ReadAll(br)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != "testing 1 2 3\n" {
|
||||
t.Fatalf("incorrect data %v", b)
|
||||
}
|
||||
gotData = true
|
||||
case BackupAlternateData:
|
||||
if gotAltData {
|
||||
t.Fatal("duplicate alt data")
|
||||
}
|
||||
if hdr.Name != ":ads.txt:$DATA" {
|
||||
t.Fatalf("incorrect name %s", hdr.Name)
|
||||
}
|
||||
b, err := ioutil.ReadAll(br)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != "alternate data stream\n" {
|
||||
t.Fatalf("incorrect data %v", b)
|
||||
}
|
||||
gotAltData = true
|
||||
default:
|
||||
t.Fatalf("unknown stream ID %d", hdr.Id)
|
||||
}
|
||||
}
|
||||
if !gotData || !gotAltData {
|
||||
t.Fatal("missing stream")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackupStreamWrite(t *testing.T) {
|
||||
f, err := os.Create(testFileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
w := NewBackupFileWriter(f, false)
|
||||
defer w.Close()
|
||||
|
||||
data := "testing 1 2 3\n"
|
||||
altData := "alternate stream\n"
|
||||
|
||||
br := NewBackupStreamWriter(w)
|
||||
err = br.WriteHeader(&BackupHeader{Id: BackupData, Size: int64(len(data))})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n, err := br.Write([]byte(data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(data) {
|
||||
t.Fatal("short write")
|
||||
}
|
||||
|
||||
err = br.WriteHeader(&BackupHeader{Id: BackupAlternateData, Size: int64(len(altData)), Name: ":ads.txt:$DATA"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n, err = br.Write([]byte(altData))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(altData) {
|
||||
t.Fatal("short write")
|
||||
}
|
||||
|
||||
f.Close()
|
||||
|
||||
b, err := ioutil.ReadFile(testFileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != data {
|
||||
t.Fatalf("wrong data %v", b)
|
||||
}
|
||||
|
||||
b, err = ioutil.ReadFile(testFileName + ":ads.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != altData {
|
||||
t.Fatalf("wrong data %v", b)
|
||||
}
|
||||
}
|
||||
|
||||
func makeSparseFile() error {
|
||||
os.Remove(testFileName)
|
||||
f, err := os.Create(testFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
const (
|
||||
FSCTL_SET_SPARSE = 0x000900c4
|
||||
FSCTL_SET_ZERO_DATA = 0x000980c8
|
||||
)
|
||||
|
||||
err = syscall.DeviceIoControl(syscall.Handle(f.Fd()), FSCTL_SET_SPARSE, nil, 0, nil, 0, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Write([]byte("testing 1 2 3\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Seek(1000000, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Write([]byte("more data later\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBackupSparseFile(t *testing.T) {
|
||||
err := makeSparseFile()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Open(testFileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewBackupFileReader(f, false)
|
||||
defer r.Close()
|
||||
|
||||
br := NewBackupStreamReader(r)
|
||||
for {
|
||||
hdr, err := br.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(hdr)
|
||||
}
|
||||
}
|
262
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe_test.go
generated
vendored
262
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe_test.go
generated
vendored
|
@ -1,262 +0,0 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testPipeName = `\\.\pipe\winiotestpipe`
|
||||
|
||||
func TestDialUnknownFailsImmediately(t *testing.T) {
|
||||
_, err := DialPipe(testPipeName, nil)
|
||||
if err.(*os.PathError).Err != syscall.ENOENT {
|
||||
t.Fatalf("expected ENOENT got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialListenerTimesOut(t *testing.T) {
|
||||
l, err := ListenPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
var d = time.Duration(10 * time.Millisecond)
|
||||
_, err = DialPipe(testPipeName, &d)
|
||||
if err != ErrTimeout {
|
||||
t.Fatalf("expected ErrTimeout, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
|
||||
c := PipeConfig{
|
||||
SecurityDescriptor: "D:P(A;;0x1200FF;;;WD)",
|
||||
}
|
||||
l, err := ListenPipe(testPipeName, &c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
_, err = DialPipe(testPipeName, nil)
|
||||
if err.(*os.PathError).Err != syscall.ERROR_ACCESS_DENIED {
|
||||
t.Fatalf("expected ERROR_ACCESS_DENIED, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func getConnection(cfg *PipeConfig) (client net.Conn, server net.Conn, err error) {
|
||||
l, err := ListenPipe(testPipeName, cfg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
type response struct {
|
||||
c net.Conn
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
c, err := l.Accept()
|
||||
ch <- response{c, err}
|
||||
}()
|
||||
|
||||
c, err := DialPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r := <-ch
|
||||
if err = r.err; err != nil {
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
||||
client = c
|
||||
server = r.c
|
||||
return
|
||||
}
|
||||
|
||||
func TestReadTimeout(t *testing.T) {
|
||||
c, s, err := getConnection(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
defer s.Close()
|
||||
|
||||
c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
|
||||
|
||||
buf := make([]byte, 10)
|
||||
_, err = c.Read(buf)
|
||||
if err != ErrTimeout {
|
||||
t.Fatalf("expected ErrTimeout, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func server(l net.Listener, ch chan int) {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
|
||||
s, err := rw.ReadString('\n')
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = rw.WriteString("got " + s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = rw.Flush()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.Close()
|
||||
ch <- 1
|
||||
}
|
||||
|
||||
func TestFullListenDialReadWrite(t *testing.T) {
|
||||
l, err := ListenPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
ch := make(chan int)
|
||||
go server(l, ch)
|
||||
|
||||
c, err := DialPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
|
||||
_, err = rw.WriteString("hello world\n")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = rw.Flush()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := rw.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ms := "got hello world\n"
|
||||
if s != ms {
|
||||
t.Errorf("expected '%s', got '%s'", ms, s)
|
||||
}
|
||||
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestCloseAbortsListen(t *testing.T) {
|
||||
l, err := ListenPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
_, err := l.Accept()
|
||||
ch <- err
|
||||
}()
|
||||
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
l.Close()
|
||||
|
||||
err = <-ch
|
||||
if err != ErrPipeListenerClosed {
|
||||
t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ensureEOFOnClose(t *testing.T, r io.Reader, w io.Closer) {
|
||||
b := make([]byte, 10)
|
||||
w.Close()
|
||||
n, err := r.Read(b)
|
||||
if n > 0 {
|
||||
t.Errorf("unexpected byte count %d", n)
|
||||
}
|
||||
if err != io.EOF {
|
||||
t.Errorf("expected EOF: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseClientEOFServer(t *testing.T) {
|
||||
c, s, err := getConnection(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
defer s.Close()
|
||||
ensureEOFOnClose(t, c, s)
|
||||
}
|
||||
|
||||
func TestCloseServerEOFClient(t *testing.T) {
|
||||
c, s, err := getConnection(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
defer s.Close()
|
||||
ensureEOFOnClose(t, s, c)
|
||||
}
|
||||
|
||||
func TestCloseWriteEOF(t *testing.T) {
|
||||
cfg := &PipeConfig{
|
||||
MessageMode: true,
|
||||
}
|
||||
c, s, err := getConnection(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
defer s.Close()
|
||||
|
||||
type closeWriter interface {
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
err = c.(closeWriter).CloseWrite()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b := make([]byte, 10)
|
||||
_, err = s.Read(b)
|
||||
if err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptAfterCloseFails(t *testing.T) {
|
||||
l, err := ListenPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l.Close()
|
||||
_, err = l.Accept()
|
||||
if err != ErrPipeListenerClosed {
|
||||
t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialTimesOutByDefault(t *testing.T) {
|
||||
l, err := ListenPipe(testPipeName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
_, err = DialPipe(testPipeName, nil)
|
||||
if err != ErrTimeout {
|
||||
t.Fatalf("expected ErrTimeout, got %v", err)
|
||||
}
|
||||
}
|
17
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/privileges_test.go
generated
vendored
17
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/privileges_test.go
generated
vendored
|
@ -1,17 +0,0 @@
|
|||
package winio
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRunWithUnavailablePrivilege(t *testing.T) {
|
||||
err := RunWithPrivilege("SeCreateTokenPrivilege", func() error { return nil })
|
||||
if _, ok := err.(*PrivilegeError); err == nil || !ok {
|
||||
t.Fatal("expected PrivilegeError")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunWithPrivileges(t *testing.T) {
|
||||
err := RunWithPrivilege("SeShutdownPrivilege", func() error { return nil })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
26
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd_test.go
generated
vendored
26
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd_test.go
generated
vendored
|
@ -1,26 +0,0 @@
|
|||
package winio
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLookupInvalidSid(t *testing.T) {
|
||||
_, err := LookupSidByName(".\\weoifjdsklfj")
|
||||
aerr, ok := err.(*AccountLookupError)
|
||||
if !ok || aerr.Err != cERROR_NONE_MAPPED {
|
||||
t.Fatalf("expected AccountLookupError with ERROR_NONE_MAPPED, got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupValidSid(t *testing.T) {
|
||||
sid, err := LookupSidByName("Everyone")
|
||||
if err != nil || sid != "S-1-1-0" {
|
||||
t.Fatal("expected S-1-1-0, got %s, %s", sid, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupEmptyNameFails(t *testing.T) {
|
||||
_, err := LookupSidByName(".\\weoifjdsklfj")
|
||||
aerr, ok := err.(*AccountLookupError)
|
||||
if !ok || aerr.Err != cERROR_NONE_MAPPED {
|
||||
t.Fatalf("expected AccountLookupError with ERROR_NONE_MAPPED, got %s", err)
|
||||
}
|
||||
}
|
46
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go
generated
vendored
46
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go
generated
vendored
|
@ -1,46 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInmemSignal(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
|
||||
sig := NewInmemSignal(inm, syscall.SIGUSR1, buf)
|
||||
defer sig.Stop()
|
||||
|
||||
inm.SetGauge([]string{"foo"}, 42)
|
||||
inm.EmitKey([]string{"bar"}, 42)
|
||||
inm.IncrCounter([]string{"baz"}, 42)
|
||||
inm.AddSample([]string{"wow"}, 42)
|
||||
|
||||
// Wait for period to end
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
|
||||
// Send signal!
|
||||
syscall.Kill(os.Getpid(), syscall.SIGUSR1)
|
||||
|
||||
// Wait for flush
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// Check the output
|
||||
out := string(buf.Bytes())
|
||||
if !strings.Contains(out, "[G] 'foo': 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[P] 'bar': 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[C] 'baz': Count: 1 Sum: 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[S] 'wow': Count: 1 Sum: 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
}
|
95
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_test.go
generated
vendored
95
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_test.go
generated
vendored
|
@ -1,95 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInmemSink(t *testing.T) {
|
||||
inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
|
||||
|
||||
data := inm.Data()
|
||||
if len(data) != 1 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
|
||||
// Add data points
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
inm.EmitKey([]string{"foo", "bar"}, 42)
|
||||
inm.IncrCounter([]string{"foo", "bar"}, 20)
|
||||
inm.IncrCounter([]string{"foo", "bar"}, 22)
|
||||
inm.AddSample([]string{"foo", "bar"}, 20)
|
||||
inm.AddSample([]string{"foo", "bar"}, 22)
|
||||
|
||||
data = inm.Data()
|
||||
if len(data) != 1 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
|
||||
intvM := data[0]
|
||||
intvM.RLock()
|
||||
|
||||
if time.Now().Sub(intvM.Interval) > 10*time.Millisecond {
|
||||
t.Fatalf("interval too old")
|
||||
}
|
||||
if intvM.Gauges["foo.bar"] != 42 {
|
||||
t.Fatalf("bad val: %v", intvM.Gauges)
|
||||
}
|
||||
if intvM.Points["foo.bar"][0] != 42 {
|
||||
t.Fatalf("bad val: %v", intvM.Points)
|
||||
}
|
||||
|
||||
agg := intvM.Counters["foo.bar"]
|
||||
if agg.Count != 2 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Sum != 42 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.SumSq != 884 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Min != 20 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Max != 22 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Mean() != 21 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Stddev() != math.Sqrt(2) {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
|
||||
if agg = intvM.Samples["foo.bar"]; agg == nil {
|
||||
t.Fatalf("missing sample")
|
||||
}
|
||||
|
||||
intvM.RUnlock()
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
data = inm.Data()
|
||||
if len(data) != min(i+1, 5) {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
}
|
||||
|
||||
// Should not exceed 5 intervals!
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
data = inm.Data()
|
||||
if len(data) != 5 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
262
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go
generated
vendored
262
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go
generated
vendored
|
@ -1,262 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mockMetric() (*MockSink, *Metrics) {
|
||||
m := &MockSink{}
|
||||
met := &Metrics{sink: m}
|
||||
return m, met
|
||||
}
|
||||
|
||||
func TestMetrics_SetGauge(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.HostName = "test"
|
||||
met.EnableHostname = true
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "test" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "gauge" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_EmitKey(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "kv" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_IncrCounter(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "counter" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_AddSample(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "sample" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_MeasureSince(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
n := time.Now()
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
met.EnableTypePrefix = true
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "timer" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
met.ServiceName = "service"
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_EmitRuntimeStats(t *testing.T) {
|
||||
runtime.GC()
|
||||
m, met := mockMetric()
|
||||
met.emitRuntimeStats()
|
||||
|
||||
if m.keys[0][0] != "runtime" || m.keys[0][1] != "num_goroutines" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[0] <= 1 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[1][0] != "runtime" || m.keys[1][1] != "alloc_bytes" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[1] <= 100000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[2][0] != "runtime" || m.keys[2][1] != "sys_bytes" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[2] <= 100000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[3][0] != "runtime" || m.keys[3][1] != "malloc_count" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[3] <= 100 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[4][0] != "runtime" || m.keys[4][1] != "free_count" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[4] <= 100 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[5][0] != "runtime" || m.keys[5][1] != "heap_objects" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[5] <= 200 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[6][0] != "runtime" || m.keys[6][1] != "total_gc_pause_ns" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[6] <= 100000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[7][0] != "runtime" || m.keys[7][1] != "total_gc_runs" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[7] <= 1 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[8][0] != "runtime" || m.keys[8][1] != "gc_pause_ns" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[8] <= 1000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
k := []string{"hi", "bob"}
|
||||
exp := []string{"hi", "there", "bob"}
|
||||
out := insert(1, "there", k)
|
||||
if !reflect.DeepEqual(exp, out) {
|
||||
t.Fatalf("bad insert %v %v", exp, out)
|
||||
}
|
||||
}
|
120
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink_test.go
generated
vendored
120
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink_test.go
generated
vendored
|
@ -1,120 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MockSink struct {
|
||||
keys [][]string
|
||||
vals []float32
|
||||
}
|
||||
|
||||
func (m *MockSink) SetGauge(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) EmitKey(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) IncrCounter(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) AddSample(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
|
||||
func TestFanoutSink_Gauge(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.SetGauge(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Key(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.EmitKey(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Counter(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.IncrCounter(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Sample(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.AddSample(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
110
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start_test.go
generated
vendored
110
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start_test.go
generated
vendored
|
@ -1,110 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDefaultConfig(t *testing.T) {
|
||||
conf := DefaultConfig("service")
|
||||
if conf.ServiceName != "service" {
|
||||
t.Fatalf("Bad name")
|
||||
}
|
||||
if conf.HostName == "" {
|
||||
t.Fatalf("missing hostname")
|
||||
}
|
||||
if !conf.EnableHostname || !conf.EnableRuntimeMetrics {
|
||||
t.Fatalf("expect true")
|
||||
}
|
||||
if conf.EnableTypePrefix {
|
||||
t.Fatalf("expect false")
|
||||
}
|
||||
if conf.TimerGranularity != time.Millisecond {
|
||||
t.Fatalf("bad granularity")
|
||||
}
|
||||
if conf.ProfileInterval != time.Second {
|
||||
t.Fatalf("bad interval")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_SetGauge(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
SetGauge(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_EmitKey(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
EmitKey(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_IncrCounter(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
IncrCounter(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_AddSample(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
AddSample(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_MeasureSince(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
globalMetrics.TimerGranularity = time.Millisecond
|
||||
|
||||
k := []string{"test"}
|
||||
now := time.Now()
|
||||
MeasureSince(k, now)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("val too large %v", m.vals[0])
|
||||
}
|
||||
}
|
105
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd_test.go
generated
vendored
105
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd_test.go
generated
vendored
|
@ -1,105 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStatsd_Flatten(t *testing.T) {
|
||||
s := &StatsdSink{}
|
||||
flat := s.flattenKey([]string{"a", "b", "c", "d"})
|
||||
if flat != "a.b.c.d" {
|
||||
t.Fatalf("Bad flat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsd_PushFullQueue(t *testing.T) {
|
||||
q := make(chan string, 1)
|
||||
q <- "full"
|
||||
|
||||
s := &StatsdSink{metricQueue: q}
|
||||
s.pushMetric("omit")
|
||||
|
||||
out := <-q
|
||||
if out != "full" {
|
||||
t.Fatalf("bad val %v", out)
|
||||
}
|
||||
|
||||
select {
|
||||
case v := <-q:
|
||||
t.Fatalf("bad val %v", v)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsd_Conn(t *testing.T) {
|
||||
addr := "127.0.0.1:7524"
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
list, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 7524})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer list.Close()
|
||||
buf := make([]byte, 1500)
|
||||
n, err := list.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf = buf[:n]
|
||||
reader := bufio.NewReader(bytes.NewReader(buf))
|
||||
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "gauge.val:1.000000|g\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "key.other:2.000000|kv\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "counter.me:3.000000|c\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "sample.slow_thingy:4.000000|ms\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
done <- true
|
||||
}()
|
||||
s, err := NewStatsdSink(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("bad error")
|
||||
}
|
||||
|
||||
s.SetGauge([]string{"gauge", "val"}, float32(1))
|
||||
s.EmitKey([]string{"key", "other"}, float32(2))
|
||||
s.IncrCounter([]string{"counter", "me"}, float32(3))
|
||||
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
s.Shutdown()
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("timeout")
|
||||
}
|
||||
}
|
101
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go
generated
vendored
101
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go
generated
vendored
|
@ -1,101 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func acceptConn(addr string) net.Conn {
|
||||
ln, _ := net.Listen("tcp", addr)
|
||||
conn, _ := ln.Accept()
|
||||
return conn
|
||||
}
|
||||
|
||||
func TestStatsite_Flatten(t *testing.T) {
|
||||
s := &StatsiteSink{}
|
||||
flat := s.flattenKey([]string{"a", "b", "c", "d"})
|
||||
if flat != "a.b.c.d" {
|
||||
t.Fatalf("Bad flat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsite_PushFullQueue(t *testing.T) {
|
||||
q := make(chan string, 1)
|
||||
q <- "full"
|
||||
|
||||
s := &StatsiteSink{metricQueue: q}
|
||||
s.pushMetric("omit")
|
||||
|
||||
out := <-q
|
||||
if out != "full" {
|
||||
t.Fatalf("bad val %v", out)
|
||||
}
|
||||
|
||||
select {
|
||||
case v := <-q:
|
||||
t.Fatalf("bad val %v", v)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsite_Conn(t *testing.T) {
|
||||
addr := "localhost:7523"
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
conn := acceptConn(addr)
|
||||
reader := bufio.NewReader(conn)
|
||||
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "gauge.val:1.000000|g\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "key.other:2.000000|kv\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "counter.me:3.000000|c\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "sample.slow_thingy:4.000000|ms\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
done <- true
|
||||
}()
|
||||
s, err := NewStatsiteSink(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("bad error")
|
||||
}
|
||||
|
||||
s.SetGauge([]string{"gauge", "val"}, float32(1))
|
||||
s.EmitKey([]string{"key", "other"}, float32(2))
|
||||
s.IncrCounter([]string{"counter", "me"}, float32(3))
|
||||
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
s.Shutdown()
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("timeout")
|
||||
}
|
||||
}
|
50
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/Makefile
generated
vendored
50
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/Makefile
generated
vendored
|
@ -1,54 +1,18 @@
|
|||
TEST=.
|
||||
BENCH=.
|
||||
COVERPROFILE=/tmp/c.out
|
||||
BRANCH=`git rev-parse --abbrev-ref HEAD`
|
||||
COMMIT=`git rev-parse --short HEAD`
|
||||
GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)"
|
||||
|
||||
default: build
|
||||
|
||||
bench:
|
||||
go test -v -test.run=NOTHINCONTAINSTHIS -test.bench=$(BENCH)
|
||||
|
||||
# http://cloc.sourceforge.net/
|
||||
cloc:
|
||||
@cloc --not-match-f='Makefile|_test.go' .
|
||||
|
||||
cover: fmt
|
||||
go test -coverprofile=$(COVERPROFILE) -test.run=$(TEST) $(COVERFLAG) .
|
||||
go tool cover -html=$(COVERPROFILE)
|
||||
rm $(COVERPROFILE)
|
||||
|
||||
cpuprofile: fmt
|
||||
@go test -c
|
||||
@./bolt.test -test.v -test.run=$(TEST) -test.cpuprofile cpu.prof
|
||||
race:
|
||||
@go test -v -race -test.run="TestSimulate_(100op|1000op)"
|
||||
|
||||
# go get github.com/kisielk/errcheck
|
||||
errcheck:
|
||||
@echo "=== errcheck ==="
|
||||
@errcheck github.com/boltdb/bolt
|
||||
@errcheck -ignorepkg=bytes -ignore=os:Remove github.com/boltdb/bolt
|
||||
|
||||
fmt:
|
||||
@go fmt ./...
|
||||
test:
|
||||
@go test -v -cover .
|
||||
@go test -v ./cmd/bolt
|
||||
|
||||
get:
|
||||
@go get -d ./...
|
||||
|
||||
build: get
|
||||
@mkdir -p bin
|
||||
@go build -ldflags=$(GOLDFLAGS) -a -o bin/bolt ./cmd/bolt
|
||||
|
||||
test: fmt
|
||||
@go get github.com/stretchr/testify/assert
|
||||
@echo "=== TESTS ==="
|
||||
@go test -v -cover -test.run=$(TEST)
|
||||
@echo ""
|
||||
@echo ""
|
||||
@echo "=== CLI ==="
|
||||
@go test -v -test.run=$(TEST) ./cmd/bolt
|
||||
@echo ""
|
||||
@echo ""
|
||||
@echo "=== RACE DETECTOR ==="
|
||||
@go test -v -race -test.run="TestSimulate_(100op|1000op)"
|
||||
|
||||
.PHONY: bench cloc cover cpuprofile fmt memprofile test
|
||||
.PHONY: fmt test
|
||||
|
|
273
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/README.md
generated
vendored
273
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/README.md
generated
vendored
|
@ -1,8 +1,8 @@
|
|||
Bolt [](https://drone.io/github.com/boltdb/bolt/latest) [](https://coveralls.io/r/boltdb/bolt?branch=master) [](https://godoc.org/github.com/boltdb/bolt) 
|
||||
Bolt [](https://drone.io/github.com/boltdb/bolt/latest) [](https://coveralls.io/r/boltdb/bolt?branch=master) [](https://godoc.org/github.com/boltdb/bolt) 
|
||||
====
|
||||
|
||||
Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas] and
|
||||
the [LMDB project][lmdb]. The goal of the project is to provide a simple,
|
||||
Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas]
|
||||
[LMDB project][lmdb]. The goal of the project is to provide a simple,
|
||||
fast, and reliable database for projects that don't require a full database
|
||||
server such as Postgres or MySQL.
|
||||
|
||||
|
@ -13,7 +13,6 @@ and setting values. That's it.
|
|||
[hyc_symas]: https://twitter.com/hyc_symas
|
||||
[lmdb]: http://symas.com/mdb/
|
||||
|
||||
|
||||
## Project Status
|
||||
|
||||
Bolt is stable and the API is fixed. Full unit test coverage and randomized
|
||||
|
@ -22,6 +21,36 @@ Bolt is currently in high-load production environments serving databases as
|
|||
large as 1TB. Many companies such as Shopify and Heroku use Bolt-backed
|
||||
services every day.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Getting Started](#getting-started)
|
||||
- [Installing](#installing)
|
||||
- [Opening a database](#opening-a-database)
|
||||
- [Transactions](#transactions)
|
||||
- [Read-write transactions](#read-write-transactions)
|
||||
- [Read-only transactions](#read-only-transactions)
|
||||
- [Batch read-write transactions](#batch-read-write-transactions)
|
||||
- [Managing transactions manually](#managing-transactions-manually)
|
||||
- [Using buckets](#using-buckets)
|
||||
- [Using key/value pairs](#using-keyvalue-pairs)
|
||||
- [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket)
|
||||
- [Iterating over keys](#iterating-over-keys)
|
||||
- [Prefix scans](#prefix-scans)
|
||||
- [Range scans](#range-scans)
|
||||
- [ForEach()](#foreach)
|
||||
- [Nested buckets](#nested-buckets)
|
||||
- [Database backups](#database-backups)
|
||||
- [Statistics](#statistics)
|
||||
- [Read-Only Mode](#read-only-mode)
|
||||
- [Mobile Use (iOS/Android)](#mobile-use-iosandroid)
|
||||
- [Resources](#resources)
|
||||
- [Comparison with other databases](#comparison-with-other-databases)
|
||||
- [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases)
|
||||
- [LevelDB, RocksDB](#leveldb-rocksdb)
|
||||
- [LMDB](#lmdb)
|
||||
- [Caveats & Limitations](#caveats--limitations)
|
||||
- [Reading the Source](#reading-the-source)
|
||||
- [Other Projects Using Bolt](#other-projects-using-bolt)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
@ -180,8 +209,8 @@ and then safely close your transaction if an error is returned. This is the
|
|||
recommended way to use Bolt transactions.
|
||||
|
||||
However, sometimes you may want to manually start and end your transactions.
|
||||
You can use the `Tx.Begin()` function directly but _please_ be sure to close the
|
||||
transaction.
|
||||
You can use the `Tx.Begin()` function directly but **please** be sure to close
|
||||
the transaction.
|
||||
|
||||
```go
|
||||
// Start a writable transaction.
|
||||
|
@ -256,7 +285,7 @@ db.View(func(tx *bolt.Tx) error {
|
|||
```
|
||||
|
||||
The `Get()` function does not return an error because its operation is
|
||||
guarenteed to work (unless there is some kind of system failure). If the key
|
||||
guaranteed to work (unless there is some kind of system failure). If the key
|
||||
exists then it will return its byte slice value. If it doesn't exist then it
|
||||
will return `nil`. It's important to note that you can have a zero-length value
|
||||
set to a key which is different than the key not existing.
|
||||
|
@ -268,6 +297,49 @@ transaction is open. If you need to use a value outside of the transaction
|
|||
then you must use `copy()` to copy it to another byte slice.
|
||||
|
||||
|
||||
### Autoincrementing integer for the bucket
|
||||
By using the `NextSequence()` function, you can let Bolt determine a sequence
|
||||
which can be used as the unique identifier for your key/value pairs. See the
|
||||
example below.
|
||||
|
||||
```go
|
||||
// CreateUser saves u to the store. The new user ID is set on u once the data is persisted.
|
||||
func (s *Store) CreateUser(u *User) error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
// Retrieve the users bucket.
|
||||
// This should be created when the DB is first opened.
|
||||
b := tx.Bucket([]byte("users"))
|
||||
|
||||
// Generate ID for the user.
|
||||
// This returns an error only if the Tx is closed or not writeable.
|
||||
// That can't happen in an Update() call so I ignore the error check.
|
||||
id, _ = b.NextSequence()
|
||||
u.ID = int(id)
|
||||
|
||||
// Marshal user data into bytes.
|
||||
buf, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Persist bytes to users bucket.
|
||||
return b.Put(itob(u.ID), buf)
|
||||
})
|
||||
}
|
||||
|
||||
// itob returns an 8-byte big endian representation of v.
|
||||
func itob(v int) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(v))
|
||||
return b
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Iterating over keys
|
||||
|
||||
Bolt stores its keys in byte-sorted order within a bucket. This makes sequential
|
||||
|
@ -276,7 +348,9 @@ iteration over these keys extremely fast. To iterate over keys we'll use a
|
|||
|
||||
```go
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
// Assume bucket exists and has keys
|
||||
b := tx.Bucket([]byte("MyBucket"))
|
||||
|
||||
c := b.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
|
@ -300,10 +374,15 @@ Next() Move to the next key.
|
|||
Prev() Move to the previous key.
|
||||
```
|
||||
|
||||
When you have iterated to the end of the cursor then `Next()` will return `nil`.
|
||||
You must seek to a position using `First()`, `Last()`, or `Seek()` before
|
||||
calling `Next()` or `Prev()`. If you do not seek to a position then these
|
||||
functions will return `nil`.
|
||||
Each of those functions has a return signature of `(key []byte, value []byte)`.
|
||||
When you have iterated to the end of the cursor then `Next()` will return a
|
||||
`nil` key. You must seek to a position using `First()`, `Last()`, or `Seek()`
|
||||
before calling `Next()` or `Prev()`. If you do not seek to a position then
|
||||
these functions will return a `nil` key.
|
||||
|
||||
During iteration, if the key is non-`nil` but the value is `nil`, that means
|
||||
the key refers to a bucket rather than a value. Use `Bucket.Bucket()` to
|
||||
access the sub-bucket.
|
||||
|
||||
|
||||
#### Prefix scans
|
||||
|
@ -312,6 +391,7 @@ To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`:
|
|||
|
||||
```go
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
// Assume bucket exists and has keys
|
||||
c := tx.Bucket([]byte("MyBucket")).Cursor()
|
||||
|
||||
prefix := []byte("1234")
|
||||
|
@ -331,7 +411,7 @@ date range like this:
|
|||
|
||||
```go
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
// Assume our events bucket has RFC3339 encoded time keys.
|
||||
// Assume our events bucket exists and has RFC3339 encoded time keys.
|
||||
c := tx.Bucket([]byte("Events")).Cursor()
|
||||
|
||||
// Our time range spans the 90's decade.
|
||||
|
@ -355,7 +435,9 @@ all the keys in a bucket:
|
|||
|
||||
```go
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
// Assume bucket exists and has keys
|
||||
b := tx.Bucket([]byte("MyBucket"))
|
||||
|
||||
b.ForEach(func(k, v []byte) error {
|
||||
fmt.Printf("key=%s, value=%s\n", k, v)
|
||||
return nil
|
||||
|
@ -382,8 +464,11 @@ func (*Bucket) DeleteBucket(key []byte) error
|
|||
Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()`
|
||||
function to write a consistent view of the database to a writer. If you call
|
||||
this from a read-only transaction, it will perform a hot backup and not block
|
||||
your other database reads and writes. It will also use `O_DIRECT` when available
|
||||
to prevent page cache trashing.
|
||||
your other database reads and writes.
|
||||
|
||||
By default, it will use a regular file handle which will utilize the operating
|
||||
system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx)
|
||||
documentation for information about optimizing for larger-than-RAM datasets.
|
||||
|
||||
One common use case is to backup over HTTP so you can use tools like `cURL` to
|
||||
do database backups:
|
||||
|
@ -465,6 +550,84 @@ if err != nil {
|
|||
}
|
||||
```
|
||||
|
||||
### Mobile Use (iOS/Android)
|
||||
|
||||
Bolt is able to run on mobile devices by leveraging the binding feature of the
|
||||
[gomobile](https://github.com/golang/mobile) tool. Create a struct that will
|
||||
contain your database logic and a reference to a `*bolt.DB` with a initializing
|
||||
contstructor that takes in a filepath where the database file will be stored.
|
||||
Neither Android nor iOS require extra permissions or cleanup from using this method.
|
||||
|
||||
```go
|
||||
func NewBoltDB(filepath string) *BoltDB {
|
||||
db, err := bolt.Open(filepath+"/demo.db", 0600, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return &BoltDB{db}
|
||||
}
|
||||
|
||||
type BoltDB struct {
|
||||
db *bolt.DB
|
||||
...
|
||||
}
|
||||
|
||||
func (b *BoltDB) Path() string {
|
||||
return b.db.Path()
|
||||
}
|
||||
|
||||
func (b *BoltDB) Close() {
|
||||
b.db.Close()
|
||||
}
|
||||
```
|
||||
|
||||
Database logic should be defined as methods on this wrapper struct.
|
||||
|
||||
To initialize this struct from the native language (both platforms now sync
|
||||
their local storage to the cloud. These snippets disable that functionality for the
|
||||
database file):
|
||||
|
||||
#### Android
|
||||
|
||||
```java
|
||||
String path;
|
||||
if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){
|
||||
path = getNoBackupFilesDir().getAbsolutePath();
|
||||
} else{
|
||||
path = getFilesDir().getAbsolutePath();
|
||||
}
|
||||
Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path)
|
||||
```
|
||||
|
||||
#### iOS
|
||||
|
||||
```objc
|
||||
- (void)demo {
|
||||
NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
NSUserDomainMask,
|
||||
YES) objectAtIndex:0];
|
||||
GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path);
|
||||
[self addSkipBackupAttributeToItemAtPath:demo.path];
|
||||
//Some DB Logic would go here
|
||||
[demo close];
|
||||
}
|
||||
|
||||
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
|
||||
{
|
||||
NSURL* URL= [NSURL fileURLWithPath: filePathString];
|
||||
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
|
||||
forKey: NSURLIsExcludedFromBackupKey error: &error];
|
||||
if(!success){
|
||||
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
|
@ -500,7 +663,7 @@ they are libraries bundled into the application, however, their underlying
|
|||
structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes
|
||||
random writes by using a write ahead log and multi-tiered, sorted files called
|
||||
SSTables. Bolt uses a B+tree internally and only a single file. Both approaches
|
||||
have trade offs.
|
||||
have trade-offs.
|
||||
|
||||
If you require a high random write throughput (>10,000 w/sec) or you need to use
|
||||
spinning disks then LevelDB could be a good choice. If your application is
|
||||
|
@ -536,9 +699,8 @@ It's important to pick the right tool for the job and Bolt is no exception.
|
|||
Here are a few things to note when evaluating and using Bolt:
|
||||
|
||||
* Bolt is good for read intensive workloads. Sequential write performance is
|
||||
also fast but random writes can be slow. You can add a write-ahead log or
|
||||
[transaction coalescer](https://github.com/boltdb/coalescer) in front of Bolt
|
||||
to mitigate this issue.
|
||||
also fast but random writes can be slow. You can use `DB.Batch()` or add a
|
||||
write-ahead log to help mitigate this issue.
|
||||
|
||||
* Bolt uses a B+tree internally so there can be a lot of random page access.
|
||||
SSDs provide a significant performance boost over spinning disks.
|
||||
|
@ -568,11 +730,13 @@ Here are a few things to note when evaluating and using Bolt:
|
|||
can in memory and will release memory as needed to other processes. This means
|
||||
that Bolt can show very high memory usage when working with large databases.
|
||||
However, this is expected and the OS will release memory as needed. Bolt can
|
||||
handle databases much larger than the available physical RAM.
|
||||
handle databases much larger than the available physical RAM, provided its
|
||||
memory-map fits in the process virtual address space. It may be problematic
|
||||
on 32-bits systems.
|
||||
|
||||
* The data structures in the Bolt database are memory mapped so the data file
|
||||
will be endian specific. This means that you cannot copy a Bolt file from a
|
||||
little endian machine to a big endian machine and have it work. For most
|
||||
little endian machine to a big endian machine and have it work. For most
|
||||
users this is not a concern since most modern CPUs are little endian.
|
||||
|
||||
* Because of the way pages are laid out on disk, Bolt cannot truncate data files
|
||||
|
@ -587,6 +751,56 @@ Here are a few things to note when evaluating and using Bolt:
|
|||
[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638
|
||||
|
||||
|
||||
## Reading the Source
|
||||
|
||||
Bolt is a relatively small code base (<3KLOC) for an embedded, serializable,
|
||||
transactional key/value database so it can be a good starting point for people
|
||||
interested in how databases work.
|
||||
|
||||
The best places to start are the main entry points into Bolt:
|
||||
|
||||
- `Open()` - Initializes the reference to the database. It's responsible for
|
||||
creating the database if it doesn't exist, obtaining an exclusive lock on the
|
||||
file, reading the meta pages, & memory-mapping the file.
|
||||
|
||||
- `DB.Begin()` - Starts a read-only or read-write transaction depending on the
|
||||
value of the `writable` argument. This requires briefly obtaining the "meta"
|
||||
lock to keep track of open transactions. Only one read-write transaction can
|
||||
exist at a time so the "rwlock" is acquired during the life of a read-write
|
||||
transaction.
|
||||
|
||||
- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the
|
||||
arguments, a cursor is used to traverse the B+tree to the page and position
|
||||
where they key & value will be written. Once the position is found, the bucket
|
||||
materializes the underlying page and the page's parent pages into memory as
|
||||
"nodes". These nodes are where mutations occur during read-write transactions.
|
||||
These changes get flushed to disk during commit.
|
||||
|
||||
- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor
|
||||
to move to the page & position of a key/value pair. During a read-only
|
||||
transaction, the key and value data is returned as a direct reference to the
|
||||
underlying mmap file so there's no allocation overhead. For read-write
|
||||
transactions, this data may reference the mmap file or one of the in-memory
|
||||
node values.
|
||||
|
||||
- `Cursor` - This object is simply for traversing the B+tree of on-disk pages
|
||||
or in-memory nodes. It can seek to a specific key, move to the first or last
|
||||
value, or it can move forward or backward. The cursor handles the movement up
|
||||
and down the B+tree transparently to the end user.
|
||||
|
||||
- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages
|
||||
into pages to be written to disk. Writing to disk then occurs in two phases.
|
||||
First, the dirty pages are written to disk and an `fsync()` occurs. Second, a
|
||||
new meta page with an incremented transaction ID is written and another
|
||||
`fsync()` occurs. This two phase write ensures that partially written data
|
||||
pages are ignored in the event of a crash since the meta page pointing to them
|
||||
is never written. Partially written meta pages are invalidated because they
|
||||
are written with a checksum.
|
||||
|
||||
If you have additional notes that could be helpful for others, please submit
|
||||
them via pull request.
|
||||
|
||||
|
||||
## Other Projects Using Bolt
|
||||
|
||||
Below is a list of public, open source projects that use Bolt:
|
||||
|
@ -597,25 +811,34 @@ Below is a list of public, open source projects that use Bolt:
|
|||
* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics.
|
||||
* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects.
|
||||
* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday.
|
||||
* [ChainStore](https://github.com/nulayer/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
|
||||
* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
|
||||
* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
|
||||
* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
|
||||
* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka.
|
||||
* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed.
|
||||
* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt.
|
||||
* [photosite/session](http://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
|
||||
* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
|
||||
* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage.
|
||||
* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
|
||||
* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend.
|
||||
* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend.
|
||||
* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server.
|
||||
* [SkyDB](https://github.com/skydb/sky) - Behavioral analytics database.
|
||||
* [Seaweed File System](https://github.com/chrislusf/weed-fs) - Highly scalable distributed key~file system with O(1) disk read.
|
||||
* [InfluxDB](http://influxdb.com) - Scalable datastore for metrics, events, and real-time analytics.
|
||||
* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read.
|
||||
* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
|
||||
* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data.
|
||||
* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
|
||||
* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware.
|
||||
* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistant, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs.
|
||||
* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs.
|
||||
* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems.
|
||||
* [stow](https://github.com/djherbis/stow) - a persistence manager for objects
|
||||
backed by boltdb.
|
||||
* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining
|
||||
simple tx and key scans.
|
||||
* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.
|
||||
* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service
|
||||
* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service.
|
||||
* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners.
|
||||
* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores.
|
||||
|
||||
If you are using Bolt in a project please send a pull request to add it to the list.
|
||||
|
|
18
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml
generated
vendored
Normal file
18
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/appveyor.yml
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
version: "{build}"
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\boltdb\bolt
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
install:
|
||||
- echo %PATH%
|
||||
- echo %GOPATH%
|
||||
- go version
|
||||
- go env
|
||||
- go get -v -t ./...
|
||||
|
||||
build_script:
|
||||
- go test -v ./...
|
138
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch.go
generated
vendored
138
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch.go
generated
vendored
|
@ -1,138 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Batch calls fn as part of a batch. It behaves similar to Update,
|
||||
// except:
|
||||
//
|
||||
// 1. concurrent Batch calls can be combined into a single Bolt
|
||||
// transaction.
|
||||
//
|
||||
// 2. the function passed to Batch may be called multiple times,
|
||||
// regardless of whether it returns error or not.
|
||||
//
|
||||
// This means that Batch function side effects must be idempotent and
|
||||
// take permanent effect only after a successful return is seen in
|
||||
// caller.
|
||||
//
|
||||
// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
|
||||
// and DB.MaxBatchDelay, respectively.
|
||||
//
|
||||
// Batch is only useful when there are multiple goroutines calling it.
|
||||
func (db *DB) Batch(fn func(*Tx) error) error {
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
db.batchMu.Lock()
|
||||
if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
|
||||
// There is no existing batch, or the existing batch is full; start a new one.
|
||||
db.batch = &batch{
|
||||
db: db,
|
||||
}
|
||||
db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
|
||||
}
|
||||
db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
|
||||
if len(db.batch.calls) >= db.MaxBatchSize {
|
||||
// wake up batch, it's ready to run
|
||||
go db.batch.trigger()
|
||||
}
|
||||
db.batchMu.Unlock()
|
||||
|
||||
err := <-errCh
|
||||
if err == trySolo {
|
||||
err = db.Update(fn)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type call struct {
|
||||
fn func(*Tx) error
|
||||
err chan<- error
|
||||
}
|
||||
|
||||
type batch struct {
|
||||
db *DB
|
||||
timer *time.Timer
|
||||
start sync.Once
|
||||
calls []call
|
||||
}
|
||||
|
||||
// trigger runs the batch if it hasn't already been run.
|
||||
func (b *batch) trigger() {
|
||||
b.start.Do(b.run)
|
||||
}
|
||||
|
||||
// run performs the transactions in the batch and communicates results
|
||||
// back to DB.Batch.
|
||||
func (b *batch) run() {
|
||||
b.db.batchMu.Lock()
|
||||
b.timer.Stop()
|
||||
// Make sure no new work is added to this batch, but don't break
|
||||
// other batches.
|
||||
if b.db.batch == b {
|
||||
b.db.batch = nil
|
||||
}
|
||||
b.db.batchMu.Unlock()
|
||||
|
||||
retry:
|
||||
for len(b.calls) > 0 {
|
||||
var failIdx = -1
|
||||
err := b.db.Update(func(tx *Tx) error {
|
||||
for i, c := range b.calls {
|
||||
if err := safelyCall(c.fn, tx); err != nil {
|
||||
failIdx = i
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if failIdx >= 0 {
|
||||
// take the failing transaction out of the batch. it's
|
||||
// safe to shorten b.calls here because db.batch no longer
|
||||
// points to us, and we hold the mutex anyway.
|
||||
c := b.calls[failIdx]
|
||||
b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
|
||||
// tell the submitter re-run it solo, continue with the rest of the batch
|
||||
c.err <- trySolo
|
||||
continue retry
|
||||
}
|
||||
|
||||
// pass success, or bolt internal errors, to all callers
|
||||
for _, c := range b.calls {
|
||||
if c.err != nil {
|
||||
c.err <- err
|
||||
}
|
||||
}
|
||||
break retry
|
||||
}
|
||||
}
|
||||
|
||||
// trySolo is a special sentinel error value used for signaling that a
|
||||
// transaction function should be re-run. It should never be seen by
|
||||
// callers.
|
||||
var trySolo = errors.New("batch function returned an error and should be re-run solo")
|
||||
|
||||
type panicked struct {
|
||||
reason interface{}
|
||||
}
|
||||
|
||||
func (p panicked) Error() string {
|
||||
if err, ok := p.reason.(error); ok {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("panic: %v", p.reason)
|
||||
}
|
||||
|
||||
func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
err = panicked{p}
|
||||
}
|
||||
}()
|
||||
return fn(tx)
|
||||
}
|
170
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_benchmark_test.go
generated
vendored
170
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_benchmark_test.go
generated
vendored
|
@ -1,170 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash/fnv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
func validateBatchBench(b *testing.B, db *TestDB) {
|
||||
var rollback = errors.New("sentinel error to cause rollback")
|
||||
validate := func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte("bench"))
|
||||
h := fnv.New32a()
|
||||
buf := make([]byte, 4)
|
||||
for id := uint32(0); id < 1000; id++ {
|
||||
binary.LittleEndian.PutUint32(buf, id)
|
||||
h.Reset()
|
||||
h.Write(buf[:])
|
||||
k := h.Sum(nil)
|
||||
v := bucket.Get(k)
|
||||
if v == nil {
|
||||
b.Errorf("not found id=%d key=%x", id, k)
|
||||
continue
|
||||
}
|
||||
if g, e := v, []byte("filler"); !bytes.Equal(g, e) {
|
||||
b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e)
|
||||
}
|
||||
if err := bucket.Delete(k); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// should be empty now
|
||||
c := bucket.Cursor()
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
b.Errorf("unexpected key: %x = %q", k, v)
|
||||
}
|
||||
return rollback
|
||||
}
|
||||
if err := db.Update(validate); err != nil && err != rollback {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDBBatchAutomatic(b *testing.B) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("bench"))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
start := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for round := 0; round < 1000; round++ {
|
||||
wg.Add(1)
|
||||
|
||||
go func(id uint32) {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
|
||||
h := fnv.New32a()
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, id)
|
||||
h.Write(buf[:])
|
||||
k := h.Sum(nil)
|
||||
insert := func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("bench"))
|
||||
return b.Put(k, []byte("filler"))
|
||||
}
|
||||
if err := db.Batch(insert); err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
}(uint32(round))
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
validateBatchBench(b, db)
|
||||
}
|
||||
|
||||
func BenchmarkDBBatchSingle(b *testing.B) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("bench"))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
start := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for round := 0; round < 1000; round++ {
|
||||
wg.Add(1)
|
||||
go func(id uint32) {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
|
||||
h := fnv.New32a()
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, id)
|
||||
h.Write(buf[:])
|
||||
k := h.Sum(nil)
|
||||
insert := func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("bench"))
|
||||
return b.Put(k, []byte("filler"))
|
||||
}
|
||||
if err := db.Update(insert); err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
}(uint32(round))
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
validateBatchBench(b, db)
|
||||
}
|
||||
|
||||
func BenchmarkDBBatchManual10x100(b *testing.B) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("bench"))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
start := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for major := 0; major < 10; major++ {
|
||||
wg.Add(1)
|
||||
go func(id uint32) {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
|
||||
insert100 := func(tx *bolt.Tx) error {
|
||||
h := fnv.New32a()
|
||||
buf := make([]byte, 4)
|
||||
for minor := uint32(0); minor < 100; minor++ {
|
||||
binary.LittleEndian.PutUint32(buf, uint32(id*100+minor))
|
||||
h.Reset()
|
||||
h.Write(buf[:])
|
||||
k := h.Sum(nil)
|
||||
b := tx.Bucket([]byte("bench"))
|
||||
if err := b.Put(k, []byte("filler")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := db.Update(insert100); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}(uint32(major))
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
validateBatchBench(b, db)
|
||||
}
|
148
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_example_test.go
generated
vendored
148
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_example_test.go
generated
vendored
|
@ -1,148 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// Set this to see how the counts are actually updated.
|
||||
const verbose = false
|
||||
|
||||
// Counter updates a counter in Bolt for every URL path requested.
|
||||
type counter struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
func (c counter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
// Communicates the new count from a successful database
|
||||
// transaction.
|
||||
var result uint64
|
||||
|
||||
increment := func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucketIfNotExists([]byte("hits"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := []byte(req.URL.String())
|
||||
// Decode handles key not found for us.
|
||||
count := decode(b.Get(key)) + 1
|
||||
b.Put(key, encode(count))
|
||||
// All good, communicate new count.
|
||||
result = count
|
||||
return nil
|
||||
}
|
||||
if err := c.db.Batch(increment); err != nil {
|
||||
http.Error(rw, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
if verbose {
|
||||
log.Printf("server: %s: %d", req.URL.String(), result)
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/octet-stream")
|
||||
fmt.Fprintf(rw, "%d\n", result)
|
||||
}
|
||||
|
||||
func client(id int, base string, paths []string) error {
|
||||
// Process paths in random order.
|
||||
rng := rand.New(rand.NewSource(int64(id)))
|
||||
permutation := rng.Perm(len(paths))
|
||||
|
||||
for i := range paths {
|
||||
path := paths[permutation[i]]
|
||||
resp, err := http.Get(base + path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if verbose {
|
||||
log.Printf("client: %s: %s", path, buf)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExampleDB_Batch() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Start our web server
|
||||
count := counter{db}
|
||||
srv := httptest.NewServer(count)
|
||||
defer srv.Close()
|
||||
|
||||
// Decrease the batch size to make things more interesting.
|
||||
db.MaxBatchSize = 3
|
||||
|
||||
// Get every path multiple times concurrently.
|
||||
const clients = 10
|
||||
paths := []string{
|
||||
"/foo",
|
||||
"/bar",
|
||||
"/baz",
|
||||
"/quux",
|
||||
"/thud",
|
||||
"/xyzzy",
|
||||
}
|
||||
errors := make(chan error, clients)
|
||||
for i := 0; i < clients; i++ {
|
||||
go func(id int) {
|
||||
errors <- client(id, srv.URL, paths)
|
||||
}(i)
|
||||
}
|
||||
// Check all responses to make sure there's no error.
|
||||
for i := 0; i < clients; i++ {
|
||||
if err := <-errors; err != nil {
|
||||
fmt.Printf("client error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check the final result
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("hits"))
|
||||
c := b.Cursor()
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
fmt.Printf("hits to %s: %d\n", k, decode(v))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// hits to /bar: 10
|
||||
// hits to /baz: 10
|
||||
// hits to /foo: 10
|
||||
// hits to /quux: 10
|
||||
// hits to /thud: 10
|
||||
// hits to /xyzzy: 10
|
||||
}
|
||||
|
||||
// encode marshals a counter.
|
||||
func encode(n uint64) []byte {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, n)
|
||||
return buf
|
||||
}
|
||||
|
||||
// decode unmarshals a counter. Nil buffers are decoded as 0.
|
||||
func decode(buf []byte) uint64 {
|
||||
if buf == nil {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint64(buf)
|
||||
}
|
167
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_test.go
generated
vendored
167
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/batch_test.go
generated
vendored
|
@ -1,167 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// Ensure two functions can perform updates in a single batch.
|
||||
func TestDB_Batch(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("widgets"))
|
||||
|
||||
// Iterate over multiple updates in separate goroutines.
|
||||
n := 2
|
||||
ch := make(chan error)
|
||||
for i := 0; i < n; i++ {
|
||||
go func(i int) {
|
||||
ch <- db.Batch(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
||||
})
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Check all responses to make sure there's no error.
|
||||
for i := 0; i < n; i++ {
|
||||
if err := <-ch; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure data is correct.
|
||||
db.MustView(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
for i := 0; i < n; i++ {
|
||||
if v := b.Get(u64tob(uint64(i))); v == nil {
|
||||
t.Errorf("key not found: %d", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestDB_Batch_Panic(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var sentinel int
|
||||
var bork = &sentinel
|
||||
var problem interface{}
|
||||
var err error
|
||||
|
||||
// Execute a function inside a batch that panics.
|
||||
func() {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
problem = p
|
||||
}
|
||||
}()
|
||||
err = db.Batch(func(tx *bolt.Tx) error {
|
||||
panic(bork)
|
||||
})
|
||||
}()
|
||||
|
||||
// Verify there is no error.
|
||||
if g, e := err, error(nil); g != e {
|
||||
t.Fatalf("wrong error: %v != %v", g, e)
|
||||
}
|
||||
// Verify the panic was captured.
|
||||
if g, e := problem, bork; g != e {
|
||||
t.Fatalf("wrong error: %v != %v", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDB_BatchFull(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("widgets"))
|
||||
|
||||
const size = 3
|
||||
// buffered so we never leak goroutines
|
||||
ch := make(chan error, size)
|
||||
put := func(i int) {
|
||||
ch <- db.Batch(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
||||
})
|
||||
}
|
||||
|
||||
db.MaxBatchSize = size
|
||||
// high enough to never trigger here
|
||||
db.MaxBatchDelay = 1 * time.Hour
|
||||
|
||||
go put(1)
|
||||
go put(2)
|
||||
|
||||
// Give the batch a chance to exhibit bugs.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// not triggered yet
|
||||
select {
|
||||
case <-ch:
|
||||
t.Fatalf("batch triggered too early")
|
||||
default:
|
||||
}
|
||||
|
||||
go put(3)
|
||||
|
||||
// Check all responses to make sure there's no error.
|
||||
for i := 0; i < size; i++ {
|
||||
if err := <-ch; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure data is correct.
|
||||
db.MustView(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
for i := 1; i <= size; i++ {
|
||||
if v := b.Get(u64tob(uint64(i))); v == nil {
|
||||
t.Errorf("key not found: %d", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestDB_BatchTime(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.MustCreateBucket([]byte("widgets"))
|
||||
|
||||
const size = 1
|
||||
// buffered so we never leak goroutines
|
||||
ch := make(chan error, size)
|
||||
put := func(i int) {
|
||||
ch <- db.Batch(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
||||
})
|
||||
}
|
||||
|
||||
db.MaxBatchSize = 1000
|
||||
db.MaxBatchDelay = 0
|
||||
|
||||
go put(1)
|
||||
|
||||
// Batch must trigger by time alone.
|
||||
|
||||
// Check all responses to make sure there's no error.
|
||||
for i := 0; i < size; i++ {
|
||||
if err := <-ch; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure data is correct.
|
||||
db.MustView(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
for i := 1; i <= size; i++ {
|
||||
if v := b.Get(u64tob(uint64(i))); v == nil {
|
||||
t.Errorf("key not found: %d", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_arm64.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_arm64.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build arm64
|
||||
|
||||
package bolt
|
||||
|
||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||
const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||
|
||||
// maxAllocSize is the size used when creating array pointers.
|
||||
const maxAllocSize = 0x7FFFFFFF
|
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_linux.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_linux.go
generated
vendored
|
@ -4,8 +4,6 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
var odirect = syscall.O_DIRECT
|
||||
|
||||
// fdatasync flushes written data to a file descriptor.
|
||||
func fdatasync(db *DB) error {
|
||||
return syscall.Fdatasync(int(db.file.Fd()))
|
||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_openbsd.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_openbsd.go
generated
vendored
|
@ -11,8 +11,6 @@ const (
|
|||
msInvalidate // invalidate cached data
|
||||
)
|
||||
|
||||
var odirect int
|
||||
|
||||
func msync(db *DB) error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate)
|
||||
if errno != 0 {
|
||||
|
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build ppc
|
||||
|
||||
package bolt
|
||||
|
||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||
const maxMapSize = 0x7FFFFFFF // 2GB
|
||||
|
||||
// maxAllocSize is the size used when creating array pointers.
|
||||
const maxAllocSize = 0xFFFFFFF
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc64.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc64.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build ppc64
|
||||
|
||||
package bolt
|
||||
|
||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||
const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||
|
||||
// maxAllocSize is the size used when creating array pointers.
|
||||
const maxAllocSize = 0x7FFFFFFF
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc64le.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_ppc64le.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build ppc64le
|
||||
|
||||
package bolt
|
||||
|
||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||
const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||
|
||||
// maxAllocSize is the size used when creating array pointers.
|
||||
const maxAllocSize = 0x7FFFFFFF
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_s390x.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_s390x.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build s390x
|
||||
|
||||
package bolt
|
||||
|
||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||
const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||
|
||||
// maxAllocSize is the size used when creating array pointers.
|
||||
const maxAllocSize = 0x7FFFFFFF
|
36
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_test.go
generated
vendored
36
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_test.go
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// assert fails the test if the condition is false.
|
||||
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
|
||||
if !condition {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// ok fails the test if an err is not nil.
|
||||
func ok(tb testing.TB, err error) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// equals fails the test if exp is not equal to act.
|
||||
func equals(tb testing.TB, exp, act interface{}) {
|
||||
if !reflect.DeepEqual(exp, act) {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
23
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix.go
generated
vendored
23
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !windows,!plan9
|
||||
// +build !windows,!plan9,!solaris
|
||||
|
||||
package bolt
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File, exclusive bool, timeout time.Duration) error {
|
||||
func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
|
||||
var t time.Time
|
||||
for {
|
||||
// If we're beyond our timeout then return an error.
|
||||
|
@ -27,7 +27,7 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
|
|||
}
|
||||
|
||||
// Otherwise attempt to obtain an exclusive lock.
|
||||
err := syscall.Flock(int(f.Fd()), flag|syscall.LOCK_NB)
|
||||
err := syscall.Flock(int(db.file.Fd()), flag|syscall.LOCK_NB)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if err != syscall.EWOULDBLOCK {
|
||||
|
@ -40,25 +40,14 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
|
|||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
|
||||
func funlock(db *DB) error {
|
||||
return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
func mmap(db *DB, sz int) error {
|
||||
// Truncate and fsync to ensure file size metadata is flushed.
|
||||
// https://github.com/boltdb/bolt/issues/284
|
||||
if !db.NoGrowSync && !db.readOnly {
|
||||
if err := db.file.Truncate(int64(sz)); err != nil {
|
||||
return fmt.Errorf("file resize error: %s", err)
|
||||
}
|
||||
if err := db.file.Sync(); err != nil {
|
||||
return fmt.Errorf("file sync error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Map the data file to memory.
|
||||
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
90
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix_solaris.go
generated
vendored
Normal file
90
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
|
||||
var t time.Time
|
||||
for {
|
||||
// If we're beyond our timeout then return an error.
|
||||
// This can only occur after we've attempted a flock once.
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
} else if timeout > 0 && time.Since(t) > timeout {
|
||||
return ErrTimeout
|
||||
}
|
||||
var lock syscall.Flock_t
|
||||
lock.Start = 0
|
||||
lock.Len = 0
|
||||
lock.Pid = 0
|
||||
lock.Whence = 0
|
||||
lock.Pid = 0
|
||||
if exclusive {
|
||||
lock.Type = syscall.F_WRLCK
|
||||
} else {
|
||||
lock.Type = syscall.F_RDLCK
|
||||
}
|
||||
err := syscall.FcntlFlock(db.file.Fd(), syscall.F_SETLK, &lock)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if err != syscall.EAGAIN {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for a bit and try again.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(db *DB) error {
|
||||
var lock syscall.Flock_t
|
||||
lock.Start = 0
|
||||
lock.Len = 0
|
||||
lock.Type = syscall.F_UNLCK
|
||||
lock.Whence = 0
|
||||
return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
func mmap(db *DB, sz int) error {
|
||||
// Map the data file to memory.
|
||||
b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Advise the kernel that the mmap is accessed randomly.
|
||||
if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
|
||||
return fmt.Errorf("madvise: %s", err)
|
||||
}
|
||||
|
||||
// Save the original byte slice and convert to a byte array pointer.
|
||||
db.dataref = b
|
||||
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
|
||||
db.datasz = sz
|
||||
return nil
|
||||
}
|
||||
|
||||
// munmap unmaps a DB's data file from memory.
|
||||
func munmap(db *DB) error {
|
||||
// Ignore the unmap if we have no mapped data.
|
||||
if db.dataref == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmap using the original byte slice.
|
||||
err := unix.Munmap(db.dataref)
|
||||
db.dataref = nil
|
||||
db.data = nil
|
||||
db.datasz = 0
|
||||
return err
|
||||
}
|
78
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_windows.go
generated
vendored
78
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bolt_windows.go
generated
vendored
|
@ -8,7 +8,39 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
var odirect int
|
||||
// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||
procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
|
||||
)
|
||||
|
||||
const (
|
||||
lockExt = ".lock"
|
||||
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
|
||||
flagLockExclusive = 2
|
||||
flagLockFailImmediately = 1
|
||||
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
|
||||
errLockViolation syscall.Errno = 0x21
|
||||
)
|
||||
|
||||
func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
||||
r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
||||
r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fdatasync flushes written data to a file descriptor.
|
||||
func fdatasync(db *DB) error {
|
||||
|
@ -16,13 +48,49 @@ func fdatasync(db *DB) error {
|
|||
}
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File, _ bool, _ time.Duration) error {
|
||||
return nil
|
||||
func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
|
||||
// Create a separate lock file on windows because a process
|
||||
// cannot share an exclusive lock on the same file. This is
|
||||
// needed during Tx.WriteTo().
|
||||
f, err := os.OpenFile(db.path+lockExt, os.O_CREATE, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.lockfile = f
|
||||
|
||||
var t time.Time
|
||||
for {
|
||||
// If we're beyond our timeout then return an error.
|
||||
// This can only occur after we've attempted a flock once.
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
} else if timeout > 0 && time.Since(t) > timeout {
|
||||
return ErrTimeout
|
||||
}
|
||||
|
||||
var flag uint32 = flagLockFailImmediately
|
||||
if exclusive {
|
||||
flag |= flagLockExclusive
|
||||
}
|
||||
|
||||
err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if err != errLockViolation {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for a bit and try again.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(f *os.File) error {
|
||||
return nil
|
||||
func funlock(db *DB) error {
|
||||
err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{})
|
||||
db.lockfile.Close()
|
||||
os.Remove(db.path+lockExt)
|
||||
return err
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/boltsync_unix.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/boltsync_unix.go
generated
vendored
|
@ -2,8 +2,6 @@
|
|||
|
||||
package bolt
|
||||
|
||||
var odirect int
|
||||
|
||||
// fdatasync flushes written data to a file descriptor.
|
||||
func fdatasync(db *DB) error {
|
||||
return db.file.Sync()
|
||||
|
|
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bucket.go
generated
vendored
9
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bucket.go
generated
vendored
|
@ -11,7 +11,7 @@ const (
|
|||
MaxKeySize = 32768
|
||||
|
||||
// MaxValueSize is the maximum length of a value, in bytes.
|
||||
MaxValueSize = 4294967295
|
||||
MaxValueSize = (1 << 31) - 2
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -99,6 +99,7 @@ func (b *Bucket) Cursor() *Cursor {
|
|||
|
||||
// Bucket retrieves a nested bucket by name.
|
||||
// Returns nil if the bucket does not exist.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (b *Bucket) Bucket(name []byte) *Bucket {
|
||||
if b.buckets != nil {
|
||||
if child := b.buckets[string(name)]; child != nil {
|
||||
|
@ -148,6 +149,7 @@ func (b *Bucket) openBucket(value []byte) *Bucket {
|
|||
|
||||
// CreateBucket creates a new bucket at the given key and returns the new bucket.
|
||||
// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
|
||||
if b.tx.db == nil {
|
||||
return nil, ErrTxClosed
|
||||
|
@ -192,6 +194,7 @@ func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
|
|||
|
||||
// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it.
|
||||
// Returns an error if the bucket name is blank, or if the bucket name is too long.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) {
|
||||
child, err := b.CreateBucket(key)
|
||||
if err == ErrBucketExists {
|
||||
|
@ -270,6 +273,7 @@ func (b *Bucket) Get(key []byte) []byte {
|
|||
|
||||
// Put sets the value for a key in the bucket.
|
||||
// If the key exist then its previous value will be overwritten.
|
||||
// Supplied value must remain valid for the life of the transaction.
|
||||
// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large.
|
||||
func (b *Bucket) Put(key []byte, value []byte) error {
|
||||
if b.tx.db == nil {
|
||||
|
@ -346,7 +350,8 @@ func (b *Bucket) NextSequence() (uint64, error) {
|
|||
|
||||
// ForEach executes a function for each key/value pair in a bucket.
|
||||
// If the provided function returns an error then the iteration is stopped and
|
||||
// the error is returned to the caller.
|
||||
// the error is returned to the caller. The provided function must not modify
|
||||
// the bucket; this will result in undefined behavior.
|
||||
func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
|
||||
if b.tx.db == nil {
|
||||
return ErrTxClosed
|
||||
|
|
1169
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bucket_test.go
generated
vendored
1169
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/bucket_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
1529
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main.go
generated
vendored
1529
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main.go
generated
vendored
File diff suppressed because it is too large
Load diff
145
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main_test.go
generated
vendored
145
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main_test.go
generated
vendored
|
@ -1,145 +0,0 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/boltdb/bolt/cmd/bolt"
|
||||
)
|
||||
|
||||
// Ensure the "info" command can print information about a database.
|
||||
func TestInfoCommand_Run(t *testing.T) {
|
||||
db := MustOpen(0666, nil)
|
||||
db.DB.Close()
|
||||
defer db.Close()
|
||||
|
||||
// Run the info command.
|
||||
m := NewMain()
|
||||
if err := m.Run("info", db.Path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the "stats" command can execute correctly.
|
||||
func TestStatsCommand_Run(t *testing.T) {
|
||||
// Ignore
|
||||
if os.Getpagesize() != 4096 {
|
||||
t.Skip("system does not use 4KB page size")
|
||||
}
|
||||
|
||||
db := MustOpen(0666, nil)
|
||||
defer db.Close()
|
||||
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
// Create "foo" bucket.
|
||||
b, err := tx.CreateBucket([]byte("foo"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create "bar" bucket.
|
||||
b, err = tx.CreateBucket([]byte("bar"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create "baz" bucket.
|
||||
b, err = tx.CreateBucket([]byte("baz"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.Put([]byte("key"), []byte("value")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
db.DB.Close()
|
||||
|
||||
// Generate expected result.
|
||||
exp := "Aggregate statistics for 3 buckets\n\n" +
|
||||
"Page count statistics\n" +
|
||||
"\tNumber of logical branch pages: 0\n" +
|
||||
"\tNumber of physical branch overflow pages: 0\n" +
|
||||
"\tNumber of logical leaf pages: 1\n" +
|
||||
"\tNumber of physical leaf overflow pages: 0\n" +
|
||||
"Tree statistics\n" +
|
||||
"\tNumber of keys/value pairs: 111\n" +
|
||||
"\tNumber of levels in B+tree: 1\n" +
|
||||
"Page size utilization\n" +
|
||||
"\tBytes allocated for physical branch pages: 0\n" +
|
||||
"\tBytes actually used for branch data: 0 (0%)\n" +
|
||||
"\tBytes allocated for physical leaf pages: 4096\n" +
|
||||
"\tBytes actually used for leaf data: 1996 (48%)\n" +
|
||||
"Bucket statistics\n" +
|
||||
"\tTotal number of buckets: 3\n" +
|
||||
"\tTotal number on inlined buckets: 2 (66%)\n" +
|
||||
"\tBytes used for inlined buckets: 236 (11%)\n"
|
||||
|
||||
// Run the command.
|
||||
m := NewMain()
|
||||
if err := m.Run("stats", db.Path); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if m.Stdout.String() != exp {
|
||||
t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Main represents a test wrapper for main.Main that records output.
|
||||
type Main struct {
|
||||
*main.Main
|
||||
Stdin bytes.Buffer
|
||||
Stdout bytes.Buffer
|
||||
Stderr bytes.Buffer
|
||||
}
|
||||
|
||||
// NewMain returns a new instance of Main.
|
||||
func NewMain() *Main {
|
||||
m := &Main{Main: main.NewMain()}
|
||||
m.Main.Stdin = &m.Stdin
|
||||
m.Main.Stdout = &m.Stdout
|
||||
m.Main.Stderr = &m.Stderr
|
||||
return m
|
||||
}
|
||||
|
||||
// MustOpen creates a Bolt database in a temporary location.
|
||||
func MustOpen(mode os.FileMode, options *bolt.Options) *DB {
|
||||
// Create temporary path.
|
||||
f, _ := ioutil.TempFile("", "bolt-")
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
|
||||
db, err := bolt.Open(f.Name(), mode, options)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return &DB{DB: db, Path: f.Name()}
|
||||
}
|
||||
|
||||
// DB is a test wrapper for bolt.DB.
|
||||
type DB struct {
|
||||
*bolt.DB
|
||||
Path string
|
||||
}
|
||||
|
||||
// Close closes and removes the database.
|
||||
func (db *DB) Close() error {
|
||||
defer os.Remove(db.Path)
|
||||
return db.DB.Close()
|
||||
}
|
54
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cursor.go
generated
vendored
54
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cursor.go
generated
vendored
|
@ -34,6 +34,13 @@ func (c *Cursor) First() (key []byte, value []byte) {
|
|||
p, n := c.bucket.pageNode(c.bucket.root)
|
||||
c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
|
||||
c.first()
|
||||
|
||||
// If we land on an empty page then move to the next value.
|
||||
// https://github.com/boltdb/bolt/issues/450
|
||||
if c.stack[len(c.stack)-1].count() == 0 {
|
||||
c.next()
|
||||
}
|
||||
|
||||
k, v, flags := c.keyValue()
|
||||
if (flags & uint32(bucketLeafFlag)) != 0 {
|
||||
return k, nil
|
||||
|
@ -209,28 +216,37 @@ func (c *Cursor) last() {
|
|||
// next moves to the next leaf element and returns the key and value.
|
||||
// If the cursor is at the last leaf element then it stays there and returns nil.
|
||||
func (c *Cursor) next() (key []byte, value []byte, flags uint32) {
|
||||
// Attempt to move over one element until we're successful.
|
||||
// Move up the stack as we hit the end of each page in our stack.
|
||||
var i int
|
||||
for i = len(c.stack) - 1; i >= 0; i-- {
|
||||
elem := &c.stack[i]
|
||||
if elem.index < elem.count()-1 {
|
||||
elem.index++
|
||||
break
|
||||
for {
|
||||
// Attempt to move over one element until we're successful.
|
||||
// Move up the stack as we hit the end of each page in our stack.
|
||||
var i int
|
||||
for i = len(c.stack) - 1; i >= 0; i-- {
|
||||
elem := &c.stack[i]
|
||||
if elem.index < elem.count()-1 {
|
||||
elem.index++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we've hit the root page then stop and return. This will leave the
|
||||
// cursor on the last element of the last page.
|
||||
if i == -1 {
|
||||
return nil, nil, 0
|
||||
}
|
||||
// If we've hit the root page then stop and return. This will leave the
|
||||
// cursor on the last element of the last page.
|
||||
if i == -1 {
|
||||
return nil, nil, 0
|
||||
}
|
||||
|
||||
// Otherwise start from where we left off in the stack and find the
|
||||
// first element of the first leaf page.
|
||||
c.stack = c.stack[:i+1]
|
||||
c.first()
|
||||
return c.keyValue()
|
||||
// Otherwise start from where we left off in the stack and find the
|
||||
// first element of the first leaf page.
|
||||
c.stack = c.stack[:i+1]
|
||||
c.first()
|
||||
|
||||
// If this is an empty page then restart and move back up the stack.
|
||||
// https://github.com/boltdb/bolt/issues/450
|
||||
if c.stack[len(c.stack)-1].count() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
return c.keyValue()
|
||||
}
|
||||
}
|
||||
|
||||
// search recursively performs a binary search against a given page/node until it finds a given key.
|
||||
|
|
511
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cursor_test.go
generated
vendored
511
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/cursor_test.go
generated
vendored
|
@ -1,511 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// Ensure that a cursor can return a reference to the bucket that created it.
|
||||
func TestCursor_Bucket(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, _ := tx.CreateBucket([]byte("widgets"))
|
||||
c := b.Cursor()
|
||||
equals(t, b, c.Bucket())
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can seek to the appropriate keys.
|
||||
func TestCursor_Seek(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
ok(t, err)
|
||||
ok(t, b.Put([]byte("foo"), []byte("0001")))
|
||||
ok(t, b.Put([]byte("bar"), []byte("0002")))
|
||||
ok(t, b.Put([]byte("baz"), []byte("0003")))
|
||||
_, err = b.CreateBucket([]byte("bkt"))
|
||||
ok(t, err)
|
||||
return nil
|
||||
})
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
|
||||
// Exact match should go to the key.
|
||||
k, v := c.Seek([]byte("bar"))
|
||||
equals(t, []byte("bar"), k)
|
||||
equals(t, []byte("0002"), v)
|
||||
|
||||
// Inexact match should go to the next key.
|
||||
k, v = c.Seek([]byte("bas"))
|
||||
equals(t, []byte("baz"), k)
|
||||
equals(t, []byte("0003"), v)
|
||||
|
||||
// Low key should go to the first key.
|
||||
k, v = c.Seek([]byte(""))
|
||||
equals(t, []byte("bar"), k)
|
||||
equals(t, []byte("0002"), v)
|
||||
|
||||
// High key should return no key.
|
||||
k, v = c.Seek([]byte("zzz"))
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
// Buckets should return their key but no value.
|
||||
k, v = c.Seek([]byte("bkt"))
|
||||
equals(t, []byte("bkt"), k)
|
||||
assert(t, v == nil, "")
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestCursor_Delete(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var count = 1000
|
||||
|
||||
// Insert every other key between 0 and $count.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, _ := tx.CreateBucket([]byte("widgets"))
|
||||
for i := 0; i < count; i += 1 {
|
||||
k := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(k, uint64(i))
|
||||
b.Put(k, make([]byte, 100))
|
||||
}
|
||||
b.CreateBucket([]byte("sub"))
|
||||
return nil
|
||||
})
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
bound := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(bound, uint64(count/2))
|
||||
for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() {
|
||||
if err := c.Delete(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.Seek([]byte("sub"))
|
||||
err := c.Delete()
|
||||
equals(t, err, bolt.ErrIncompatibleValue)
|
||||
return nil
|
||||
})
|
||||
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
equals(t, b.Stats().KeyN, count/2+1)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can seek to the appropriate keys when there are a
|
||||
// large number of keys. This test also checks that seek will always move
|
||||
// forward to the next key.
|
||||
//
|
||||
// Related: https://github.com/boltdb/bolt/pull/187
|
||||
func TestCursor_Seek_Large(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var count = 10000
|
||||
|
||||
// Insert every other key between 0 and $count.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, _ := tx.CreateBucket([]byte("widgets"))
|
||||
for i := 0; i < count; i += 100 {
|
||||
for j := i; j < i+100; j += 2 {
|
||||
k := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(k, uint64(j))
|
||||
b.Put(k, make([]byte, 100))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for i := 0; i < count; i++ {
|
||||
seek := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(seek, uint64(i))
|
||||
|
||||
k, _ := c.Seek(seek)
|
||||
|
||||
// The last seek is beyond the end of the the range so
|
||||
// it should return nil.
|
||||
if i == count-1 {
|
||||
assert(t, k == nil, "")
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise we should seek to the exact key or the next key.
|
||||
num := binary.BigEndian.Uint64(k)
|
||||
if i%2 == 0 {
|
||||
equals(t, uint64(i), num)
|
||||
} else {
|
||||
equals(t, uint64(i+1), num)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a cursor can iterate over an empty bucket without error.
|
||||
func TestCursor_EmptyBucket(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
k, v := c.First()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can reverse iterate over an empty bucket without error.
|
||||
func TestCursor_EmptyBucketReverse(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
k, v := c.Last()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can iterate over a single root with a couple elements.
|
||||
func TestCursor_Iterate_Leaf(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{})
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0})
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{1})
|
||||
return nil
|
||||
})
|
||||
tx, _ := db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
|
||||
k, v := c.First()
|
||||
equals(t, string(k), "bar")
|
||||
equals(t, v, []byte{1})
|
||||
|
||||
k, v = c.Next()
|
||||
equals(t, string(k), "baz")
|
||||
equals(t, v, []byte{})
|
||||
|
||||
k, v = c.Next()
|
||||
equals(t, string(k), "foo")
|
||||
equals(t, v, []byte{0})
|
||||
|
||||
k, v = c.Next()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
k, v = c.Next()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
tx.Rollback()
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
|
||||
func TestCursor_LeafRootReverse(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{})
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0})
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{1})
|
||||
return nil
|
||||
})
|
||||
tx, _ := db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
|
||||
k, v := c.Last()
|
||||
equals(t, string(k), "foo")
|
||||
equals(t, v, []byte{0})
|
||||
|
||||
k, v = c.Prev()
|
||||
equals(t, string(k), "baz")
|
||||
equals(t, v, []byte{})
|
||||
|
||||
k, v = c.Prev()
|
||||
equals(t, string(k), "bar")
|
||||
equals(t, v, []byte{1})
|
||||
|
||||
k, v = c.Prev()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
k, v = c.Prev()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
tx.Rollback()
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can restart from the beginning.
|
||||
func TestCursor_Restart(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{})
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{})
|
||||
return nil
|
||||
})
|
||||
|
||||
tx, _ := db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
|
||||
k, _ := c.First()
|
||||
equals(t, string(k), "bar")
|
||||
|
||||
k, _ = c.Next()
|
||||
equals(t, string(k), "foo")
|
||||
|
||||
k, _ = c.First()
|
||||
equals(t, string(k), "bar")
|
||||
|
||||
k, _ = c.Next()
|
||||
equals(t, string(k), "foo")
|
||||
|
||||
tx.Rollback()
|
||||
}
|
||||
|
||||
// Ensure that a Tx can iterate over all elements in a bucket.
|
||||
func TestCursor_QuickCheck(t *testing.T) {
|
||||
f := func(items testdata) bool {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
// Bulk insert all values.
|
||||
tx, _ := db.Begin(true)
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
for _, item := range items {
|
||||
ok(t, b.Put(item.Key, item.Value))
|
||||
}
|
||||
ok(t, tx.Commit())
|
||||
|
||||
// Sort test data.
|
||||
sort.Sort(items)
|
||||
|
||||
// Iterate over all items and check consistency.
|
||||
var index = 0
|
||||
tx, _ = db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
|
||||
equals(t, k, items[index].Key)
|
||||
equals(t, v, items[index].Value)
|
||||
index++
|
||||
}
|
||||
equals(t, len(items), index)
|
||||
tx.Rollback()
|
||||
|
||||
return true
|
||||
}
|
||||
if err := quick.Check(f, qconfig()); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a transaction can iterate over all elements in a bucket in reverse.
|
||||
func TestCursor_QuickCheck_Reverse(t *testing.T) {
|
||||
f := func(items testdata) bool {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
// Bulk insert all values.
|
||||
tx, _ := db.Begin(true)
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
for _, item := range items {
|
||||
ok(t, b.Put(item.Key, item.Value))
|
||||
}
|
||||
ok(t, tx.Commit())
|
||||
|
||||
// Sort test data.
|
||||
sort.Sort(revtestdata(items))
|
||||
|
||||
// Iterate over all items and check consistency.
|
||||
var index = 0
|
||||
tx, _ = db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
|
||||
equals(t, k, items[index].Key)
|
||||
equals(t, v, items[index].Value)
|
||||
index++
|
||||
}
|
||||
equals(t, len(items), index)
|
||||
tx.Rollback()
|
||||
|
||||
return true
|
||||
}
|
||||
if err := quick.Check(f, qconfig()); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can iterate over subbuckets.
|
||||
func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("foo"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("bar"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("baz"))
|
||||
ok(t, err)
|
||||
return nil
|
||||
})
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
var names []string
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
names = append(names, string(k))
|
||||
assert(t, v == nil, "")
|
||||
}
|
||||
equals(t, names, []string{"bar", "baz", "foo"})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx cursor can reverse iterate over subbuckets.
|
||||
func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("foo"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("bar"))
|
||||
ok(t, err)
|
||||
_, err = b.CreateBucket([]byte("baz"))
|
||||
ok(t, err)
|
||||
return nil
|
||||
})
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
var names []string
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for k, v := c.Last(); k != nil; k, v = c.Prev() {
|
||||
names = append(names, string(k))
|
||||
assert(t, v == nil, "")
|
||||
}
|
||||
equals(t, names, []string{"foo", "baz", "bar"})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func ExampleCursor() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Start a read-write transaction.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
// Create a new bucket.
|
||||
tx.CreateBucket([]byte("animals"))
|
||||
|
||||
// Insert data into a bucket.
|
||||
b := tx.Bucket([]byte("animals"))
|
||||
b.Put([]byte("dog"), []byte("fun"))
|
||||
b.Put([]byte("cat"), []byte("lame"))
|
||||
b.Put([]byte("liger"), []byte("awesome"))
|
||||
|
||||
// Create a cursor for iteration.
|
||||
c := b.Cursor()
|
||||
|
||||
// Iterate over items in sorted key order. This starts from the
|
||||
// first key/value pair and updates the k/v variables to the
|
||||
// next key/value on each iteration.
|
||||
//
|
||||
// The loop finishes at the end of the cursor when a nil key is returned.
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
fmt.Printf("A %s is %s.\n", k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// A cat is lame.
|
||||
// A dog is fun.
|
||||
// A liger is awesome.
|
||||
}
|
||||
|
||||
func ExampleCursor_reverse() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Start a read-write transaction.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
// Create a new bucket.
|
||||
tx.CreateBucket([]byte("animals"))
|
||||
|
||||
// Insert data into a bucket.
|
||||
b := tx.Bucket([]byte("animals"))
|
||||
b.Put([]byte("dog"), []byte("fun"))
|
||||
b.Put([]byte("cat"), []byte("lame"))
|
||||
b.Put([]byte("liger"), []byte("awesome"))
|
||||
|
||||
// Create a cursor for iteration.
|
||||
c := b.Cursor()
|
||||
|
||||
// Iterate over items in reverse sorted key order. This starts
|
||||
// from the last key/value pair and updates the k/v variables to
|
||||
// the previous key/value on each iteration.
|
||||
//
|
||||
// The loop finishes at the beginning of the cursor when a nil key
|
||||
// is returned.
|
||||
for k, v := c.Last(); k != nil; k, v = c.Prev() {
|
||||
fmt.Printf("A %s is %s.\n", k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// A liger is awesome.
|
||||
// A dog is fun.
|
||||
// A cat is lame.
|
||||
}
|
221
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/db.go
generated
vendored
221
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/db.go
generated
vendored
|
@ -1,8 +1,10 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
|
@ -24,13 +26,14 @@ const magic uint32 = 0xED0CDAED
|
|||
// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
|
||||
// syncing changes to a file. This is required as some operating systems,
|
||||
// such as OpenBSD, do not have a unified buffer cache (UBC) and writes
|
||||
// must be synchronzied using the msync(2) syscall.
|
||||
// must be synchronized using the msync(2) syscall.
|
||||
const IgnoreNoSync = runtime.GOOS == "openbsd"
|
||||
|
||||
// Default values if not set in a DB instance.
|
||||
const (
|
||||
DefaultMaxBatchSize int = 1000
|
||||
DefaultMaxBatchDelay = 10 * time.Millisecond
|
||||
DefaultAllocSize = 16 * 1024 * 1024
|
||||
)
|
||||
|
||||
// DB represents a collection of buckets persisted to a file on disk.
|
||||
|
@ -63,6 +66,10 @@ type DB struct {
|
|||
// https://github.com/boltdb/bolt/issues/284
|
||||
NoGrowSync bool
|
||||
|
||||
// If you want to read the entire database fast, you can set MmapFlag to
|
||||
// syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
|
||||
MmapFlags int
|
||||
|
||||
// MaxBatchSize is the maximum size of a batch. Default value is
|
||||
// copied from DefaultMaxBatchSize in Open.
|
||||
//
|
||||
|
@ -79,11 +86,18 @@ type DB struct {
|
|||
// Do not change concurrently with calls to Batch.
|
||||
MaxBatchDelay time.Duration
|
||||
|
||||
// AllocSize is the amount of space allocated when the database
|
||||
// needs to create new pages. This is done to amortize the cost
|
||||
// of truncate() and fsync() when growing the data file.
|
||||
AllocSize int
|
||||
|
||||
path string
|
||||
file *os.File
|
||||
lockfile *os.File // windows only
|
||||
dataref []byte // mmap'ed readonly, write throws SEGV
|
||||
data *[maxMapSize]byte
|
||||
datasz int
|
||||
filesz int // current on disk file size
|
||||
meta0 *meta
|
||||
meta1 *meta
|
||||
pageSize int
|
||||
|
@ -136,10 +150,12 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
options = DefaultOptions
|
||||
}
|
||||
db.NoGrowSync = options.NoGrowSync
|
||||
db.MmapFlags = options.MmapFlags
|
||||
|
||||
// Set default values for later DB operations.
|
||||
db.MaxBatchSize = DefaultMaxBatchSize
|
||||
db.MaxBatchDelay = DefaultMaxBatchDelay
|
||||
db.AllocSize = DefaultAllocSize
|
||||
|
||||
flag := os.O_RDWR
|
||||
if options.ReadOnly {
|
||||
|
@ -162,7 +178,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
// if !options.ReadOnly.
|
||||
// The database file is locked using the shared lock (more than one process may
|
||||
// hold a lock at the same time) otherwise (options.ReadOnly is set).
|
||||
if err := flock(db.file, !db.readOnly, options.Timeout); err != nil {
|
||||
if err := flock(db, mode, !db.readOnly, options.Timeout); err != nil {
|
||||
_ = db.close()
|
||||
return nil, err
|
||||
}
|
||||
|
@ -172,7 +188,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
|
||||
// Initialize the database if it doesn't exist.
|
||||
if info, err := db.file.Stat(); err != nil {
|
||||
return nil, fmt.Errorf("stat error: %s", err)
|
||||
return nil, err
|
||||
} else if info.Size() == 0 {
|
||||
// Initialize new files with meta pages.
|
||||
if err := db.init(); err != nil {
|
||||
|
@ -184,14 +200,14 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
|
||||
m := db.pageInBuffer(buf[:], 0).meta()
|
||||
if err := m.validate(); err != nil {
|
||||
return nil, fmt.Errorf("meta0 error: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
db.pageSize = int(m.pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Memory map the data file.
|
||||
if err := db.mmap(0); err != nil {
|
||||
if err := db.mmap(options.InitialMmapSize); err != nil {
|
||||
_ = db.close()
|
||||
return nil, err
|
||||
}
|
||||
|
@ -248,10 +264,10 @@ func (db *DB) mmap(minsz int) error {
|
|||
|
||||
// Validate the meta pages.
|
||||
if err := db.meta0.validate(); err != nil {
|
||||
return fmt.Errorf("meta0 error: %s", err)
|
||||
return err
|
||||
}
|
||||
if err := db.meta1.validate(); err != nil {
|
||||
return fmt.Errorf("meta1 error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -266,7 +282,7 @@ func (db *DB) munmap() error {
|
|||
}
|
||||
|
||||
// mmapSize determines the appropriate size for the mmap given the current size
|
||||
// of the database. The minimum size is 1MB and doubles until it reaches 1GB.
|
||||
// of the database. The minimum size is 32KB and doubles until it reaches 1GB.
|
||||
// Returns an error if the new mmap size is greater than the max allowed.
|
||||
func (db *DB) mmapSize(size int) (int, error) {
|
||||
// Double the size from 32KB until 1GB.
|
||||
|
@ -364,6 +380,10 @@ func (db *DB) Close() error {
|
|||
}
|
||||
|
||||
func (db *DB) close() error {
|
||||
if !db.opened {
|
||||
return nil
|
||||
}
|
||||
|
||||
db.opened = false
|
||||
|
||||
db.freelist = nil
|
||||
|
@ -382,7 +402,9 @@ func (db *DB) close() error {
|
|||
// No need to unlock read-only file.
|
||||
if !db.readOnly {
|
||||
// Unlock the file.
|
||||
_ = funlock(db.file)
|
||||
if err := funlock(db); err != nil {
|
||||
log.Printf("bolt.Close(): funlock error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file descriptor.
|
||||
|
@ -401,11 +423,15 @@ func (db *DB) close() error {
|
|||
// will cause the calls to block and be serialized until the current write
|
||||
// transaction finishes.
|
||||
//
|
||||
// Transactions should not be depedent on one another. Opening a read
|
||||
// Transactions should not be dependent on one another. Opening a read
|
||||
// transaction and a write transaction in the same goroutine can cause the
|
||||
// writer to deadlock because the database periodically needs to re-mmap itself
|
||||
// as it grows and it cannot do that while a read transaction is open.
|
||||
//
|
||||
// If a long running read transaction (for example, a snapshot transaction) is
|
||||
// needed, you might want to set DB.InitialMmapSize to a large enough value
|
||||
// to avoid potential blocking of write transaction.
|
||||
//
|
||||
// IMPORTANT: You must close read-only transactions after you are finished or
|
||||
// else the database will not reclaim old pages.
|
||||
func (db *DB) Begin(writable bool) (*Tx, error) {
|
||||
|
@ -589,6 +615,136 @@ func (db *DB) View(fn func(*Tx) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Batch calls fn as part of a batch. It behaves similar to Update,
|
||||
// except:
|
||||
//
|
||||
// 1. concurrent Batch calls can be combined into a single Bolt
|
||||
// transaction.
|
||||
//
|
||||
// 2. the function passed to Batch may be called multiple times,
|
||||
// regardless of whether it returns error or not.
|
||||
//
|
||||
// This means that Batch function side effects must be idempotent and
|
||||
// take permanent effect only after a successful return is seen in
|
||||
// caller.
|
||||
//
|
||||
// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
|
||||
// and DB.MaxBatchDelay, respectively.
|
||||
//
|
||||
// Batch is only useful when there are multiple goroutines calling it.
|
||||
func (db *DB) Batch(fn func(*Tx) error) error {
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
db.batchMu.Lock()
|
||||
if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
|
||||
// There is no existing batch, or the existing batch is full; start a new one.
|
||||
db.batch = &batch{
|
||||
db: db,
|
||||
}
|
||||
db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
|
||||
}
|
||||
db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
|
||||
if len(db.batch.calls) >= db.MaxBatchSize {
|
||||
// wake up batch, it's ready to run
|
||||
go db.batch.trigger()
|
||||
}
|
||||
db.batchMu.Unlock()
|
||||
|
||||
err := <-errCh
|
||||
if err == trySolo {
|
||||
err = db.Update(fn)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type call struct {
|
||||
fn func(*Tx) error
|
||||
err chan<- error
|
||||
}
|
||||
|
||||
type batch struct {
|
||||
db *DB
|
||||
timer *time.Timer
|
||||
start sync.Once
|
||||
calls []call
|
||||
}
|
||||
|
||||
// trigger runs the batch if it hasn't already been run.
|
||||
func (b *batch) trigger() {
|
||||
b.start.Do(b.run)
|
||||
}
|
||||
|
||||
// run performs the transactions in the batch and communicates results
|
||||
// back to DB.Batch.
|
||||
func (b *batch) run() {
|
||||
b.db.batchMu.Lock()
|
||||
b.timer.Stop()
|
||||
// Make sure no new work is added to this batch, but don't break
|
||||
// other batches.
|
||||
if b.db.batch == b {
|
||||
b.db.batch = nil
|
||||
}
|
||||
b.db.batchMu.Unlock()
|
||||
|
||||
retry:
|
||||
for len(b.calls) > 0 {
|
||||
var failIdx = -1
|
||||
err := b.db.Update(func(tx *Tx) error {
|
||||
for i, c := range b.calls {
|
||||
if err := safelyCall(c.fn, tx); err != nil {
|
||||
failIdx = i
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if failIdx >= 0 {
|
||||
// take the failing transaction out of the batch. it's
|
||||
// safe to shorten b.calls here because db.batch no longer
|
||||
// points to us, and we hold the mutex anyway.
|
||||
c := b.calls[failIdx]
|
||||
b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
|
||||
// tell the submitter re-run it solo, continue with the rest of the batch
|
||||
c.err <- trySolo
|
||||
continue retry
|
||||
}
|
||||
|
||||
// pass success, or bolt internal errors, to all callers
|
||||
for _, c := range b.calls {
|
||||
if c.err != nil {
|
||||
c.err <- err
|
||||
}
|
||||
}
|
||||
break retry
|
||||
}
|
||||
}
|
||||
|
||||
// trySolo is a special sentinel error value used for signaling that a
|
||||
// transaction function should be re-run. It should never be seen by
|
||||
// callers.
|
||||
var trySolo = errors.New("batch function returned an error and should be re-run solo")
|
||||
|
||||
type panicked struct {
|
||||
reason interface{}
|
||||
}
|
||||
|
||||
func (p panicked) Error() string {
|
||||
if err, ok := p.reason.(error); ok {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("panic: %v", p.reason)
|
||||
}
|
||||
|
||||
func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
err = panicked{p}
|
||||
}
|
||||
}()
|
||||
return fn(tx)
|
||||
}
|
||||
|
||||
// Sync executes fdatasync() against the database file handle.
|
||||
//
|
||||
// This is not necessary under normal operation, however, if you use NoSync
|
||||
|
@ -655,6 +811,38 @@ func (db *DB) allocate(count int) (*page, error) {
|
|||
return p, nil
|
||||
}
|
||||
|
||||
// grow grows the size of the database to the given sz.
|
||||
func (db *DB) grow(sz int) error {
|
||||
// Ignore if the new size is less than available file size.
|
||||
if sz <= db.filesz {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the data is smaller than the alloc size then only allocate what's needed.
|
||||
// Once it goes over the allocation size then allocate in chunks.
|
||||
if db.datasz < db.AllocSize {
|
||||
sz = db.datasz
|
||||
} else {
|
||||
sz += db.AllocSize
|
||||
}
|
||||
|
||||
// Truncate and fsync to ensure file size metadata is flushed.
|
||||
// https://github.com/boltdb/bolt/issues/284
|
||||
if !db.NoGrowSync && !db.readOnly {
|
||||
if runtime.GOOS != "windows" {
|
||||
if err := db.file.Truncate(int64(sz)); err != nil {
|
||||
return fmt.Errorf("file resize error: %s", err)
|
||||
}
|
||||
}
|
||||
if err := db.file.Sync(); err != nil {
|
||||
return fmt.Errorf("file sync error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
db.filesz = sz
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) IsReadOnly() bool {
|
||||
return db.readOnly
|
||||
}
|
||||
|
@ -672,6 +860,19 @@ type Options struct {
|
|||
// Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
|
||||
// grab a shared lock (UNIX).
|
||||
ReadOnly bool
|
||||
|
||||
// Sets the DB.MmapFlags flag before memory mapping the file.
|
||||
MmapFlags int
|
||||
|
||||
// InitialMmapSize is the initial mmap size of the database
|
||||
// in bytes. Read transactions won't block write transaction
|
||||
// if the InitialMmapSize is large enough to hold database mmap
|
||||
// size. (See DB.Begin for more information)
|
||||
//
|
||||
// If <=0, the initial map size is 0.
|
||||
// If initialMmapSize is smaller than the previous database size,
|
||||
// it takes no effect.
|
||||
InitialMmapSize int
|
||||
}
|
||||
|
||||
// DefaultOptions represent the options used if nil options are passed into Open().
|
||||
|
|
903
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/db_test.go
generated
vendored
903
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/db_test.go
generated
vendored
|
@ -1,903 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
var statsFlag = flag.Bool("stats", false, "show performance stats")
|
||||
|
||||
// Ensure that opening a database with a bad path returns an error.
|
||||
func TestOpen_BadPath(t *testing.T) {
|
||||
db, err := bolt.Open("", 0666, nil)
|
||||
assert(t, err != nil, "err: %s", err)
|
||||
assert(t, db == nil, "")
|
||||
}
|
||||
|
||||
// Ensure that a database can be opened without error.
|
||||
func TestOpen(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
assert(t, db != nil, "")
|
||||
ok(t, err)
|
||||
equals(t, db.Path(), path)
|
||||
ok(t, db.Close())
|
||||
}
|
||||
|
||||
// Ensure that opening an already open database file will timeout.
|
||||
func TestOpen_Timeout(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("timeout not supported on windows")
|
||||
}
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open a data file.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
assert(t, db0 != nil, "")
|
||||
ok(t, err)
|
||||
|
||||
// Attempt to open the database again.
|
||||
start := time.Now()
|
||||
db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 100 * time.Millisecond})
|
||||
assert(t, db1 == nil, "")
|
||||
equals(t, bolt.ErrTimeout, err)
|
||||
assert(t, time.Since(start) > 100*time.Millisecond, "")
|
||||
|
||||
db0.Close()
|
||||
}
|
||||
|
||||
// Ensure that opening an already open database file will wait until its closed.
|
||||
func TestOpen_Wait(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("timeout not supported on windows")
|
||||
}
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open a data file.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
assert(t, db0 != nil, "")
|
||||
ok(t, err)
|
||||
|
||||
// Close it in just a bit.
|
||||
time.AfterFunc(100*time.Millisecond, func() { db0.Close() })
|
||||
|
||||
// Attempt to open the database again.
|
||||
start := time.Now()
|
||||
db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 200 * time.Millisecond})
|
||||
assert(t, db1 != nil, "")
|
||||
ok(t, err)
|
||||
assert(t, time.Since(start) > 100*time.Millisecond, "")
|
||||
}
|
||||
|
||||
// Ensure that opening a database does not increase its size.
|
||||
// https://github.com/boltdb/bolt/issues/291
|
||||
func TestOpen_Size(t *testing.T) {
|
||||
// Open a data file.
|
||||
db := NewTestDB()
|
||||
path := db.Path()
|
||||
defer db.Close()
|
||||
|
||||
// Insert until we get above the minimum 4MB size.
|
||||
ok(t, db.Update(func(tx *bolt.Tx) error {
|
||||
b, _ := tx.CreateBucketIfNotExists([]byte("data"))
|
||||
for i := 0; i < 10000; i++ {
|
||||
ok(t, b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)))
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Close database and grab the size.
|
||||
db.DB.Close()
|
||||
sz := fileSize(path)
|
||||
if sz == 0 {
|
||||
t.Fatalf("unexpected new file size: %d", sz)
|
||||
}
|
||||
|
||||
// Reopen database, update, and check size again.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
ok(t, db0.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) }))
|
||||
ok(t, db0.Close())
|
||||
newSz := fileSize(path)
|
||||
if newSz == 0 {
|
||||
t.Fatalf("unexpected new file size: %d", newSz)
|
||||
}
|
||||
|
||||
// Compare the original size with the new size.
|
||||
if sz != newSz {
|
||||
t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that opening a database beyond the max step size does not increase its size.
|
||||
// https://github.com/boltdb/bolt/issues/303
|
||||
func TestOpen_Size_Large(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("short mode")
|
||||
}
|
||||
|
||||
// Open a data file.
|
||||
db := NewTestDB()
|
||||
path := db.Path()
|
||||
defer db.Close()
|
||||
|
||||
// Insert until we get above the minimum 4MB size.
|
||||
var index uint64
|
||||
for i := 0; i < 10000; i++ {
|
||||
ok(t, db.Update(func(tx *bolt.Tx) error {
|
||||
b, _ := tx.CreateBucketIfNotExists([]byte("data"))
|
||||
for j := 0; j < 1000; j++ {
|
||||
ok(t, b.Put(u64tob(index), make([]byte, 50)))
|
||||
index++
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// Close database and grab the size.
|
||||
db.DB.Close()
|
||||
sz := fileSize(path)
|
||||
if sz == 0 {
|
||||
t.Fatalf("unexpected new file size: %d", sz)
|
||||
} else if sz < (1 << 30) {
|
||||
t.Fatalf("expected larger initial size: %d", sz)
|
||||
}
|
||||
|
||||
// Reopen database, update, and check size again.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
ok(t, db0.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) }))
|
||||
ok(t, db0.Close())
|
||||
newSz := fileSize(path)
|
||||
if newSz == 0 {
|
||||
t.Fatalf("unexpected new file size: %d", newSz)
|
||||
}
|
||||
|
||||
// Compare the original size with the new size.
|
||||
if sz != newSz {
|
||||
t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a re-opened database is consistent.
|
||||
func TestOpen_Check(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
ok(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() }))
|
||||
db.Close()
|
||||
|
||||
db, err = bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
ok(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() }))
|
||||
db.Close()
|
||||
}
|
||||
|
||||
// Ensure that the database returns an error if the file handle cannot be open.
|
||||
func TestDB_Open_FileError(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
_, err := bolt.Open(path+"/youre-not-my-real-parent", 0666, nil)
|
||||
assert(t, err.(*os.PathError) != nil, "")
|
||||
equals(t, path+"/youre-not-my-real-parent", err.(*os.PathError).Path)
|
||||
equals(t, "open", err.(*os.PathError).Op)
|
||||
}
|
||||
|
||||
// Ensure that write errors to the meta file handler during initialization are returned.
|
||||
func TestDB_Open_MetaInitWriteError(t *testing.T) {
|
||||
t.Skip("pending")
|
||||
}
|
||||
|
||||
// Ensure that a database that is too small returns an error.
|
||||
func TestDB_Open_FileTooSmall(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
db.Close()
|
||||
|
||||
// corrupt the database
|
||||
ok(t, os.Truncate(path, int64(os.Getpagesize())))
|
||||
|
||||
db, err = bolt.Open(path, 0666, nil)
|
||||
equals(t, errors.New("file size too small"), err)
|
||||
}
|
||||
|
||||
// Ensure that a database can be opened in read-only mode by multiple processes
|
||||
// and that a database can not be opened in read-write mode and in read-only
|
||||
// mode at the same time.
|
||||
func TestOpen_ReadOnly(t *testing.T) {
|
||||
bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open in read-write mode.
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket(bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.Put(key, value)
|
||||
}))
|
||||
assert(t, db != nil, "")
|
||||
assert(t, !db.IsReadOnly(), "")
|
||||
ok(t, err)
|
||||
ok(t, db.Close())
|
||||
|
||||
// Open in read-only mode.
|
||||
db0, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
|
||||
ok(t, err)
|
||||
defer db0.Close()
|
||||
|
||||
// Opening in read-write mode should return an error.
|
||||
_, err = bolt.Open(path, 0666, &bolt.Options{Timeout: time.Millisecond * 100})
|
||||
assert(t, err != nil, "")
|
||||
|
||||
// And again (in read-only mode).
|
||||
db1, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
|
||||
ok(t, err)
|
||||
defer db1.Close()
|
||||
|
||||
// Verify both read-only databases are accessible.
|
||||
for _, db := range []*bolt.DB{db0, db1} {
|
||||
// Verify is is in read only mode indeed.
|
||||
assert(t, db.IsReadOnly(), "")
|
||||
|
||||
// Read-only databases should not allow updates.
|
||||
assert(t,
|
||||
bolt.ErrDatabaseReadOnly == db.Update(func(*bolt.Tx) error {
|
||||
panic(`should never get here`)
|
||||
}),
|
||||
"")
|
||||
|
||||
// Read-only databases should not allow beginning writable txns.
|
||||
_, err = db.Begin(true)
|
||||
assert(t, bolt.ErrDatabaseReadOnly == err, "")
|
||||
|
||||
// Verify the data.
|
||||
ok(t, db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bucket)
|
||||
if b == nil {
|
||||
return fmt.Errorf("expected bucket `%s`", string(bucket))
|
||||
}
|
||||
|
||||
got := string(b.Get(key))
|
||||
expected := string(value)
|
||||
if got != expected {
|
||||
return fmt.Errorf("expected `%s`, got `%s`", expected, got)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(benbjohnson): Test corruption at every byte of the first two pages.
|
||||
|
||||
// Ensure that a database cannot open a transaction when it's not open.
|
||||
func TestDB_Begin_DatabaseNotOpen(t *testing.T) {
|
||||
var db bolt.DB
|
||||
tx, err := db.Begin(false)
|
||||
assert(t, tx == nil, "")
|
||||
equals(t, err, bolt.ErrDatabaseNotOpen)
|
||||
}
|
||||
|
||||
// Ensure that a read-write transaction can be retrieved.
|
||||
func TestDB_BeginRW(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, err := db.Begin(true)
|
||||
assert(t, tx != nil, "")
|
||||
ok(t, err)
|
||||
assert(t, tx.DB() == db.DB, "")
|
||||
equals(t, tx.Writable(), true)
|
||||
ok(t, tx.Commit())
|
||||
}
|
||||
|
||||
// Ensure that opening a transaction while the DB is closed returns an error.
|
||||
func TestDB_BeginRW_Closed(t *testing.T) {
|
||||
var db bolt.DB
|
||||
tx, err := db.Begin(true)
|
||||
equals(t, err, bolt.ErrDatabaseNotOpen)
|
||||
assert(t, tx == nil, "")
|
||||
}
|
||||
|
||||
func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) }
|
||||
func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) }
|
||||
|
||||
// Ensure that a database cannot close while transactions are open.
|
||||
func testDB_Close_PendingTx(t *testing.T, writable bool) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
// Start transaction.
|
||||
tx, err := db.Begin(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Open update in separate goroutine.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
db.Close()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Ensure database hasn't closed.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
select {
|
||||
case <-done:
|
||||
t.Fatal("database closed too early")
|
||||
default:
|
||||
}
|
||||
|
||||
// Commit transaction.
|
||||
if err := tx.Commit(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ensure database closed now.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
select {
|
||||
case <-done:
|
||||
default:
|
||||
t.Fatal("database did not close")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a database can provide a transactional block.
|
||||
func TestDB_Update(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
err := db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
b.Put([]byte("foo"), []byte("bar"))
|
||||
b.Put([]byte("baz"), []byte("bat"))
|
||||
b.Delete([]byte("foo"))
|
||||
return nil
|
||||
})
|
||||
ok(t, err)
|
||||
err = db.View(func(tx *bolt.Tx) error {
|
||||
assert(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")) == nil, "")
|
||||
equals(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz")))
|
||||
return nil
|
||||
})
|
||||
ok(t, err)
|
||||
}
|
||||
|
||||
// Ensure a closed database returns an error while running a transaction block
|
||||
func TestDB_Update_Closed(t *testing.T) {
|
||||
var db bolt.DB
|
||||
err := db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
return nil
|
||||
})
|
||||
equals(t, err, bolt.ErrDatabaseNotOpen)
|
||||
}
|
||||
|
||||
// Ensure a panic occurs while trying to commit a managed transaction.
|
||||
func TestDB_Update_ManualCommit(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var ok bool
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
tx.Commit()
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
assert(t, ok, "expected panic")
|
||||
}
|
||||
|
||||
// Ensure a panic occurs while trying to rollback a managed transaction.
|
||||
func TestDB_Update_ManualRollback(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var ok bool
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
tx.Rollback()
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
assert(t, ok, "expected panic")
|
||||
}
|
||||
|
||||
// Ensure a panic occurs while trying to commit a managed transaction.
|
||||
func TestDB_View_ManualCommit(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var ok bool
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
tx.Commit()
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
assert(t, ok, "expected panic")
|
||||
}
|
||||
|
||||
// Ensure a panic occurs while trying to rollback a managed transaction.
|
||||
func TestDB_View_ManualRollback(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var ok bool
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
tx.Rollback()
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
assert(t, ok, "expected panic")
|
||||
}
|
||||
|
||||
// Ensure a write transaction that panics does not hold open locks.
|
||||
func TestDB_Update_Panic(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Log("recover: update", r)
|
||||
}
|
||||
}()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
panic("omg")
|
||||
})
|
||||
}()
|
||||
|
||||
// Verify we can update again.
|
||||
err := db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
ok(t, err)
|
||||
|
||||
// Verify that our change persisted.
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
assert(t, tx.Bucket([]byte("widgets")) != nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a database can return an error through a read-only transactional block.
|
||||
func TestDB_View_Error(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
err := db.View(func(tx *bolt.Tx) error {
|
||||
return errors.New("xxx")
|
||||
})
|
||||
equals(t, errors.New("xxx"), err)
|
||||
}
|
||||
|
||||
// Ensure a read transaction that panics does not hold open locks.
|
||||
func TestDB_View_Panic(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
return nil
|
||||
})
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Log("recover: view", r)
|
||||
}
|
||||
}()
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
assert(t, tx.Bucket([]byte("widgets")) != nil, "")
|
||||
panic("omg")
|
||||
})
|
||||
}()
|
||||
|
||||
// Verify that we can still use read transactions.
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
assert(t, tx.Bucket([]byte("widgets")) != nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when a database write fails.
|
||||
func TestDB_Commit_WriteFail(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
}
|
||||
|
||||
// Ensure that DB stats can be returned.
|
||||
func TestDB_Stats(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
stats := db.Stats()
|
||||
equals(t, 2, stats.TxStats.PageCount)
|
||||
equals(t, 0, stats.FreePageN)
|
||||
equals(t, 2, stats.PendingPageN)
|
||||
}
|
||||
|
||||
// Ensure that database pages are in expected order and type.
|
||||
func TestDB_Consistency(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
ok(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
p, _ := tx.Page(0)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "meta", p.Type)
|
||||
|
||||
p, _ = tx.Page(1)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "meta", p.Type)
|
||||
|
||||
p, _ = tx.Page(2)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "free", p.Type)
|
||||
|
||||
p, _ = tx.Page(3)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "free", p.Type)
|
||||
|
||||
p, _ = tx.Page(4)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "leaf", p.Type)
|
||||
|
||||
p, _ = tx.Page(5)
|
||||
assert(t, p != nil, "")
|
||||
equals(t, "freelist", p.Type)
|
||||
|
||||
p, _ = tx.Page(6)
|
||||
assert(t, p == nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that DB stats can be substracted from one another.
|
||||
func TestDBStats_Sub(t *testing.T) {
|
||||
var a, b bolt.Stats
|
||||
a.TxStats.PageCount = 3
|
||||
a.FreePageN = 4
|
||||
b.TxStats.PageCount = 10
|
||||
b.FreePageN = 14
|
||||
diff := b.Sub(&a)
|
||||
equals(t, 7, diff.TxStats.PageCount)
|
||||
// free page stats are copied from the receiver and not subtracted
|
||||
equals(t, 14, diff.FreePageN)
|
||||
}
|
||||
|
||||
func ExampleDB_Update() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Execute several commands within a write transaction.
|
||||
err := db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// If our transactional block didn't return an error then our data is saved.
|
||||
if err == nil {
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
|
||||
fmt.Printf("The value of 'foo' is: %s\n", value)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// The value of 'foo' is: bar
|
||||
}
|
||||
|
||||
func ExampleDB_View() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Insert data into a bucket.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("people"))
|
||||
b := tx.Bucket([]byte("people"))
|
||||
b.Put([]byte("john"), []byte("doe"))
|
||||
b.Put([]byte("susy"), []byte("que"))
|
||||
return nil
|
||||
})
|
||||
|
||||
// Access data from within a read-only transactional block.
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
v := tx.Bucket([]byte("people")).Get([]byte("john"))
|
||||
fmt.Printf("John's last name is %s.\n", v)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// John's last name is doe.
|
||||
}
|
||||
|
||||
func ExampleDB_Begin_ReadOnly() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Create a bucket.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
|
||||
// Create several keys in a transaction.
|
||||
tx, _ := db.Begin(true)
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
b.Put([]byte("john"), []byte("blue"))
|
||||
b.Put([]byte("abby"), []byte("red"))
|
||||
b.Put([]byte("zephyr"), []byte("purple"))
|
||||
tx.Commit()
|
||||
|
||||
// Iterate over the values in sorted key order.
|
||||
tx, _ = db.Begin(false)
|
||||
c := tx.Bucket([]byte("widgets")).Cursor()
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
fmt.Printf("%s likes %s\n", k, v)
|
||||
}
|
||||
tx.Rollback()
|
||||
|
||||
// Output:
|
||||
// abby likes red
|
||||
// john likes blue
|
||||
// zephyr likes purple
|
||||
}
|
||||
|
||||
// TestDB represents a wrapper around a Bolt DB to handle temporary file
|
||||
// creation and automatic cleanup on close.
|
||||
type TestDB struct {
|
||||
*bolt.DB
|
||||
}
|
||||
|
||||
// NewTestDB returns a new instance of TestDB.
|
||||
func NewTestDB() *TestDB {
|
||||
db, err := bolt.Open(tempfile(), 0666, nil)
|
||||
if err != nil {
|
||||
panic("cannot open db: " + err.Error())
|
||||
}
|
||||
return &TestDB{db}
|
||||
}
|
||||
|
||||
// MustView executes a read-only function. Panic on error.
|
||||
func (db *TestDB) MustView(fn func(tx *bolt.Tx) error) {
|
||||
if err := db.DB.View(func(tx *bolt.Tx) error {
|
||||
return fn(tx)
|
||||
}); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// MustUpdate executes a read-write function. Panic on error.
|
||||
func (db *TestDB) MustUpdate(fn func(tx *bolt.Tx) error) {
|
||||
if err := db.DB.View(func(tx *bolt.Tx) error {
|
||||
return fn(tx)
|
||||
}); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// MustCreateBucket creates a new bucket. Panic on error.
|
||||
func (db *TestDB) MustCreateBucket(name []byte) {
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte(name))
|
||||
return err
|
||||
}); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the database and deletes the underlying file.
|
||||
func (db *TestDB) Close() {
|
||||
// Log statistics.
|
||||
if *statsFlag {
|
||||
db.PrintStats()
|
||||
}
|
||||
|
||||
// Check database consistency after every test.
|
||||
db.MustCheck()
|
||||
|
||||
// Close database and remove file.
|
||||
defer os.Remove(db.Path())
|
||||
db.DB.Close()
|
||||
}
|
||||
|
||||
// PrintStats prints the database stats
|
||||
func (db *TestDB) PrintStats() {
|
||||
var stats = db.Stats()
|
||||
fmt.Printf("[db] %-20s %-20s %-20s\n",
|
||||
fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc),
|
||||
fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount),
|
||||
fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref),
|
||||
)
|
||||
fmt.Printf(" %-20s %-20s %-20s\n",
|
||||
fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)),
|
||||
fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)),
|
||||
fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)),
|
||||
)
|
||||
}
|
||||
|
||||
// MustCheck runs a consistency check on the database and panics if any errors are found.
|
||||
func (db *TestDB) MustCheck() {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
// Collect all the errors.
|
||||
var errors []error
|
||||
for err := range tx.Check() {
|
||||
errors = append(errors, err)
|
||||
if len(errors) > 10 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If errors occurred, copy the DB and print the errors.
|
||||
if len(errors) > 0 {
|
||||
var path = tempfile()
|
||||
tx.CopyFile(path, 0600)
|
||||
|
||||
// Print errors.
|
||||
fmt.Print("\n\n")
|
||||
fmt.Printf("consistency check failed (%d errors)\n", len(errors))
|
||||
for _, err := range errors {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("")
|
||||
fmt.Println("db saved to:")
|
||||
fmt.Println(path)
|
||||
fmt.Print("\n\n")
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CopyTempFile copies a database to a temporary file.
|
||||
func (db *TestDB) CopyTempFile() {
|
||||
path := tempfile()
|
||||
db.View(func(tx *bolt.Tx) error { return tx.CopyFile(path, 0600) })
|
||||
fmt.Println("db copied to: ", path)
|
||||
}
|
||||
|
||||
// tempfile returns a temporary file path.
|
||||
func tempfile() string {
|
||||
f, _ := ioutil.TempFile("", "bolt-")
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
// mustContainKeys checks that a bucket contains a given set of keys.
|
||||
func mustContainKeys(b *bolt.Bucket, m map[string]string) {
|
||||
found := make(map[string]string)
|
||||
b.ForEach(func(k, _ []byte) error {
|
||||
found[string(k)] = ""
|
||||
return nil
|
||||
})
|
||||
|
||||
// Check for keys found in bucket that shouldn't be there.
|
||||
var keys []string
|
||||
for k, _ := range found {
|
||||
if _, ok := m[string(k)]; !ok {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
sort.Strings(keys)
|
||||
panic(fmt.Sprintf("keys found(%d): %s", len(keys), strings.Join(keys, ",")))
|
||||
}
|
||||
|
||||
// Check for keys not found in bucket that should be there.
|
||||
for k, _ := range m {
|
||||
if _, ok := found[string(k)]; !ok {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
sort.Strings(keys)
|
||||
panic(fmt.Sprintf("keys not found(%d): %s", len(keys), strings.Join(keys, ",")))
|
||||
}
|
||||
}
|
||||
|
||||
func trunc(b []byte, length int) []byte {
|
||||
if length < len(b) {
|
||||
return b[:length]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func truncDuration(d time.Duration) string {
|
||||
return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
|
||||
}
|
||||
|
||||
func fileSize(path string) int64 {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return fi.Size()
|
||||
}
|
||||
|
||||
func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) }
|
||||
func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }
|
||||
|
||||
// u64tob converts a uint64 into an 8-byte slice.
|
||||
func u64tob(v uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, v)
|
||||
return b
|
||||
}
|
||||
|
||||
// btou64 converts an 8-byte slice into an uint64.
|
||||
func btou64(b []byte) uint64 { return binary.BigEndian.Uint64(b) }
|
156
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/freelist_test.go
generated
vendored
156
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/freelist_test.go
generated
vendored
|
@ -1,156 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Ensure that a page is added to a transaction's freelist.
|
||||
func TestFreelist_free(t *testing.T) {
|
||||
f := newFreelist()
|
||||
f.free(100, &page{id: 12})
|
||||
if !reflect.DeepEqual([]pgid{12}, f.pending[100]) {
|
||||
t.Fatalf("exp=%v; got=%v", []pgid{12}, f.pending[100])
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a page and its overflow is added to a transaction's freelist.
|
||||
func TestFreelist_free_overflow(t *testing.T) {
|
||||
f := newFreelist()
|
||||
f.free(100, &page{id: 12, overflow: 3})
|
||||
if exp := []pgid{12, 13, 14, 15}; !reflect.DeepEqual(exp, f.pending[100]) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.pending[100])
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a transaction's free pages can be released.
|
||||
func TestFreelist_release(t *testing.T) {
|
||||
f := newFreelist()
|
||||
f.free(100, &page{id: 12, overflow: 1})
|
||||
f.free(100, &page{id: 9})
|
||||
f.free(102, &page{id: 39})
|
||||
f.release(100)
|
||||
f.release(101)
|
||||
if exp := []pgid{9, 12, 13}; !reflect.DeepEqual(exp, f.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.ids)
|
||||
}
|
||||
|
||||
f.release(102)
|
||||
if exp := []pgid{9, 12, 13, 39}; !reflect.DeepEqual(exp, f.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.ids)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a freelist can find contiguous blocks of pages.
|
||||
func TestFreelist_allocate(t *testing.T) {
|
||||
f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}}
|
||||
if id := int(f.allocate(3)); id != 3 {
|
||||
t.Fatalf("exp=3; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(1)); id != 6 {
|
||||
t.Fatalf("exp=6; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(3)); id != 0 {
|
||||
t.Fatalf("exp=0; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(2)); id != 12 {
|
||||
t.Fatalf("exp=12; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(1)); id != 7 {
|
||||
t.Fatalf("exp=7; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(0)); id != 0 {
|
||||
t.Fatalf("exp=0; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(0)); id != 0 {
|
||||
t.Fatalf("exp=0; got=%v", id)
|
||||
}
|
||||
if exp := []pgid{9, 18}; !reflect.DeepEqual(exp, f.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.ids)
|
||||
}
|
||||
|
||||
if id := int(f.allocate(1)); id != 9 {
|
||||
t.Fatalf("exp=9; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(1)); id != 18 {
|
||||
t.Fatalf("exp=18; got=%v", id)
|
||||
}
|
||||
if id := int(f.allocate(1)); id != 0 {
|
||||
t.Fatalf("exp=0; got=%v", id)
|
||||
}
|
||||
if exp := []pgid{}; !reflect.DeepEqual(exp, f.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.ids)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a freelist can deserialize from a freelist page.
|
||||
func TestFreelist_read(t *testing.T) {
|
||||
// Create a page.
|
||||
var buf [4096]byte
|
||||
page := (*page)(unsafe.Pointer(&buf[0]))
|
||||
page.flags = freelistPageFlag
|
||||
page.count = 2
|
||||
|
||||
// Insert 2 page ids.
|
||||
ids := (*[3]pgid)(unsafe.Pointer(&page.ptr))
|
||||
ids[0] = 23
|
||||
ids[1] = 50
|
||||
|
||||
// Deserialize page into a freelist.
|
||||
f := newFreelist()
|
||||
f.read(page)
|
||||
|
||||
// Ensure that there are two page ids in the freelist.
|
||||
if exp := []pgid{23, 50}; !reflect.DeepEqual(exp, f.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f.ids)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a freelist can serialize into a freelist page.
|
||||
func TestFreelist_write(t *testing.T) {
|
||||
// Create a freelist and write it to a page.
|
||||
var buf [4096]byte
|
||||
f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)}
|
||||
f.pending[100] = []pgid{28, 11}
|
||||
f.pending[101] = []pgid{3}
|
||||
p := (*page)(unsafe.Pointer(&buf[0]))
|
||||
f.write(p)
|
||||
|
||||
// Read the page back out.
|
||||
f2 := newFreelist()
|
||||
f2.read(p)
|
||||
|
||||
// Ensure that the freelist is correct.
|
||||
// All pages should be present and in reverse order.
|
||||
if exp := []pgid{3, 11, 12, 28, 39}; !reflect.DeepEqual(exp, f2.ids) {
|
||||
t.Fatalf("exp=%v; got=%v", exp, f2.ids)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_FreelistRelease10K(b *testing.B) { benchmark_FreelistRelease(b, 10000) }
|
||||
func Benchmark_FreelistRelease100K(b *testing.B) { benchmark_FreelistRelease(b, 100000) }
|
||||
func Benchmark_FreelistRelease1000K(b *testing.B) { benchmark_FreelistRelease(b, 1000000) }
|
||||
func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistRelease(b, 10000000) }
|
||||
|
||||
func benchmark_FreelistRelease(b *testing.B, size int) {
|
||||
ids := randomPgids(size)
|
||||
pending := randomPgids(len(ids) / 400)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f := &freelist{ids: ids, pending: map[txid][]pgid{1: pending}}
|
||||
f.release(1)
|
||||
}
|
||||
}
|
||||
|
||||
func randomPgids(n int) []pgid {
|
||||
rand.Seed(42)
|
||||
pgids := make(pgids, n)
|
||||
for i := range pgids {
|
||||
pgids[i] = pgid(rand.Int63())
|
||||
}
|
||||
sort.Sort(pgids)
|
||||
return pgids
|
||||
}
|
37
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/node.go
generated
vendored
37
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/node.go
generated
vendored
|
@ -463,43 +463,6 @@ func (n *node) rebalance() {
|
|||
target = n.prevSibling()
|
||||
}
|
||||
|
||||
// If target node has extra nodes then just move one over.
|
||||
if target.numChildren() > target.minKeys() {
|
||||
if useNextSibling {
|
||||
// Reparent and move node.
|
||||
if child, ok := n.bucket.nodes[target.inodes[0].pgid]; ok {
|
||||
child.parent.removeChild(child)
|
||||
child.parent = n
|
||||
child.parent.children = append(child.parent.children, child)
|
||||
}
|
||||
n.inodes = append(n.inodes, target.inodes[0])
|
||||
target.inodes = target.inodes[1:]
|
||||
|
||||
// Update target key on parent.
|
||||
target.parent.put(target.key, target.inodes[0].key, nil, target.pgid, 0)
|
||||
target.key = target.inodes[0].key
|
||||
_assert(len(target.key) > 0, "rebalance(1): zero-length node key")
|
||||
} else {
|
||||
// Reparent and move node.
|
||||
if child, ok := n.bucket.nodes[target.inodes[len(target.inodes)-1].pgid]; ok {
|
||||
child.parent.removeChild(child)
|
||||
child.parent = n
|
||||
child.parent.children = append(child.parent.children, child)
|
||||
}
|
||||
n.inodes = append(n.inodes, inode{})
|
||||
copy(n.inodes[1:], n.inodes)
|
||||
n.inodes[0] = target.inodes[len(target.inodes)-1]
|
||||
target.inodes = target.inodes[:len(target.inodes)-1]
|
||||
}
|
||||
|
||||
// Update parent key for node.
|
||||
n.parent.put(n.key, n.inodes[0].key, nil, n.pgid, 0)
|
||||
n.key = n.inodes[0].key
|
||||
_assert(len(n.key) > 0, "rebalance(2): zero-length node key")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// If both this node and the target node are too small then merge them.
|
||||
if useNextSibling {
|
||||
// Reparent all child nodes being moved.
|
||||
|
|
156
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/node_test.go
generated
vendored
156
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/node_test.go
generated
vendored
|
@ -1,156 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Ensure that a node can insert a key/value.
|
||||
func TestNode_put(t *testing.T) {
|
||||
n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
|
||||
n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0)
|
||||
n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0)
|
||||
n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0)
|
||||
n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag)
|
||||
|
||||
if len(n.inodes) != 3 {
|
||||
t.Fatalf("exp=3; got=%d", len(n.inodes))
|
||||
}
|
||||
if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" {
|
||||
t.Fatalf("exp=<bar,1>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" {
|
||||
t.Fatalf("exp=<baz,2>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" {
|
||||
t.Fatalf("exp=<foo,3>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if n.inodes[2].flags != uint32(leafPageFlag) {
|
||||
t.Fatalf("not a leaf: %d", n.inodes[2].flags)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a node can deserialize from a leaf page.
|
||||
func TestNode_read_LeafPage(t *testing.T) {
|
||||
// Create a page.
|
||||
var buf [4096]byte
|
||||
page := (*page)(unsafe.Pointer(&buf[0]))
|
||||
page.flags = leafPageFlag
|
||||
page.count = 2
|
||||
|
||||
// Insert 2 elements at the beginning. sizeof(leafPageElement) == 16
|
||||
nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr))
|
||||
nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(leafPageElement) * 2
|
||||
nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4
|
||||
|
||||
// Write data for the nodes at the end.
|
||||
data := (*[4096]byte)(unsafe.Pointer(&nodes[2]))
|
||||
copy(data[:], []byte("barfooz"))
|
||||
copy(data[7:], []byte("helloworldbye"))
|
||||
|
||||
// Deserialize page into a leaf.
|
||||
n := &node{}
|
||||
n.read(page)
|
||||
|
||||
// Check that there are two inodes with correct data.
|
||||
if !n.isLeaf {
|
||||
t.Fatal("expected leaf")
|
||||
}
|
||||
if len(n.inodes) != 2 {
|
||||
t.Fatalf("exp=2; got=%d", len(n.inodes))
|
||||
}
|
||||
if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" {
|
||||
t.Fatalf("exp=<bar,fooz>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" {
|
||||
t.Fatalf("exp=<helloworld,bye>; got=<%s,%s>", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a node can serialize into a leaf page.
|
||||
func TestNode_write_LeafPage(t *testing.T) {
|
||||
// Create a node.
|
||||
n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
|
||||
n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0)
|
||||
n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0)
|
||||
n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0)
|
||||
|
||||
// Write it to a page.
|
||||
var buf [4096]byte
|
||||
p := (*page)(unsafe.Pointer(&buf[0]))
|
||||
n.write(p)
|
||||
|
||||
// Read the page back in.
|
||||
n2 := &node{}
|
||||
n2.read(p)
|
||||
|
||||
// Check that the two pages are the same.
|
||||
if len(n2.inodes) != 3 {
|
||||
t.Fatalf("exp=3; got=%d", len(n2.inodes))
|
||||
}
|
||||
if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" {
|
||||
t.Fatalf("exp=<john,johnson>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" {
|
||||
t.Fatalf("exp=<ricki,lake>; got=<%s,%s>", k, v)
|
||||
}
|
||||
if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" {
|
||||
t.Fatalf("exp=<susy,que>; got=<%s,%s>", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a node can split into appropriate subgroups.
|
||||
func TestNode_split(t *testing.T) {
|
||||
// Create a node.
|
||||
n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
|
||||
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
|
||||
|
||||
// Split between 2 & 3.
|
||||
n.split(100)
|
||||
|
||||
var parent = n.parent
|
||||
if len(parent.children) != 2 {
|
||||
t.Fatalf("exp=2; got=%d", len(parent.children))
|
||||
}
|
||||
if len(parent.children[0].inodes) != 2 {
|
||||
t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes))
|
||||
}
|
||||
if len(parent.children[1].inodes) != 3 {
|
||||
t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a page with the minimum number of inodes just returns a single node.
|
||||
func TestNode_split_MinKeys(t *testing.T) {
|
||||
// Create a node.
|
||||
n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
|
||||
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
|
||||
|
||||
// Split.
|
||||
n.split(20)
|
||||
if n.parent != nil {
|
||||
t.Fatalf("expected nil parent")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a node that has keys that all fit on a page just returns one leaf.
|
||||
func TestNode_split_SinglePage(t *testing.T) {
|
||||
// Create a node.
|
||||
n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
|
||||
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
|
||||
n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
|
||||
|
||||
// Split.
|
||||
n.split(4096)
|
||||
if n.parent != nil {
|
||||
t.Fatalf("expected nil parent")
|
||||
}
|
||||
}
|
72
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/page_test.go
generated
vendored
72
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/page_test.go
generated
vendored
|
@ -1,72 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
||||
// Ensure that the page type can be returned in human readable format.
|
||||
func TestPage_typ(t *testing.T) {
|
||||
if typ := (&page{flags: branchPageFlag}).typ(); typ != "branch" {
|
||||
t.Fatalf("exp=branch; got=%v", typ)
|
||||
}
|
||||
if typ := (&page{flags: leafPageFlag}).typ(); typ != "leaf" {
|
||||
t.Fatalf("exp=leaf; got=%v", typ)
|
||||
}
|
||||
if typ := (&page{flags: metaPageFlag}).typ(); typ != "meta" {
|
||||
t.Fatalf("exp=meta; got=%v", typ)
|
||||
}
|
||||
if typ := (&page{flags: freelistPageFlag}).typ(); typ != "freelist" {
|
||||
t.Fatalf("exp=freelist; got=%v", typ)
|
||||
}
|
||||
if typ := (&page{flags: 20000}).typ(); typ != "unknown<4e20>" {
|
||||
t.Fatalf("exp=unknown<4e20>; got=%v", typ)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the hexdump debugging function doesn't blow up.
|
||||
func TestPage_dump(t *testing.T) {
|
||||
(&page{id: 256}).hexdump(16)
|
||||
}
|
||||
|
||||
func TestPgids_merge(t *testing.T) {
|
||||
a := pgids{4, 5, 6, 10, 11, 12, 13, 27}
|
||||
b := pgids{1, 3, 8, 9, 25, 30}
|
||||
c := a.merge(b)
|
||||
if !reflect.DeepEqual(c, pgids{1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30}) {
|
||||
t.Errorf("mismatch: %v", c)
|
||||
}
|
||||
|
||||
a = pgids{4, 5, 6, 10, 11, 12, 13, 27, 35, 36}
|
||||
b = pgids{8, 9, 25, 30}
|
||||
c = a.merge(b)
|
||||
if !reflect.DeepEqual(c, pgids{4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30, 35, 36}) {
|
||||
t.Errorf("mismatch: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPgids_merge_quick(t *testing.T) {
|
||||
if err := quick.Check(func(a, b pgids) bool {
|
||||
// Sort incoming lists.
|
||||
sort.Sort(a)
|
||||
sort.Sort(b)
|
||||
|
||||
// Merge the two lists together.
|
||||
got := a.merge(b)
|
||||
|
||||
// The expected value should be the two lists combined and sorted.
|
||||
exp := append(a, b...)
|
||||
sort.Sort(exp)
|
||||
|
||||
if !reflect.DeepEqual(exp, got) {
|
||||
t.Errorf("\nexp=%+v\ngot=%+v\n", exp, got)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
79
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/quick_test.go
generated
vendored
79
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/quick_test.go
generated
vendored
|
@ -1,79 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing/quick"
|
||||
"time"
|
||||
)
|
||||
|
||||
// testing/quick defaults to 5 iterations and a random seed.
|
||||
// You can override these settings from the command line:
|
||||
//
|
||||
// -quick.count The number of iterations to perform.
|
||||
// -quick.seed The seed to use for randomizing.
|
||||
// -quick.maxitems The maximum number of items to insert into a DB.
|
||||
// -quick.maxksize The maximum size of a key.
|
||||
// -quick.maxvsize The maximum size of a value.
|
||||
//
|
||||
|
||||
var qcount, qseed, qmaxitems, qmaxksize, qmaxvsize int
|
||||
|
||||
func init() {
|
||||
flag.IntVar(&qcount, "quick.count", 5, "")
|
||||
flag.IntVar(&qseed, "quick.seed", int(time.Now().UnixNano())%100000, "")
|
||||
flag.IntVar(&qmaxitems, "quick.maxitems", 1000, "")
|
||||
flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "")
|
||||
flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "")
|
||||
flag.Parse()
|
||||
fmt.Fprintln(os.Stderr, "seed:", qseed)
|
||||
fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize)
|
||||
}
|
||||
|
||||
func qconfig() *quick.Config {
|
||||
return &quick.Config{
|
||||
MaxCount: qcount,
|
||||
Rand: rand.New(rand.NewSource(int64(qseed))),
|
||||
}
|
||||
}
|
||||
|
||||
type testdata []testdataitem
|
||||
|
||||
func (t testdata) Len() int { return len(t) }
|
||||
func (t testdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == -1 }
|
||||
|
||||
func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
n := rand.Intn(qmaxitems-1) + 1
|
||||
items := make(testdata, n)
|
||||
for i := 0; i < n; i++ {
|
||||
item := &items[i]
|
||||
item.Key = randByteSlice(rand, 1, qmaxksize)
|
||||
item.Value = randByteSlice(rand, 0, qmaxvsize)
|
||||
}
|
||||
return reflect.ValueOf(items)
|
||||
}
|
||||
|
||||
type revtestdata []testdataitem
|
||||
|
||||
func (t revtestdata) Len() int { return len(t) }
|
||||
func (t revtestdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == 1 }
|
||||
|
||||
type testdataitem struct {
|
||||
Key []byte
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte {
|
||||
n := rand.Intn(maxSize-minSize) + minSize
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
b[i] = byte(rand.Intn(255))
|
||||
}
|
||||
return b
|
||||
}
|
327
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/simulation_test.go
generated
vendored
327
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/simulation_test.go
generated
vendored
|
@ -1,327 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
func TestSimulate_1op_1p(t *testing.T) { testSimulate(t, 100, 1) }
|
||||
func TestSimulate_10op_1p(t *testing.T) { testSimulate(t, 10, 1) }
|
||||
func TestSimulate_100op_1p(t *testing.T) { testSimulate(t, 100, 1) }
|
||||
func TestSimulate_1000op_1p(t *testing.T) { testSimulate(t, 1000, 1) }
|
||||
func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, 10000, 1) }
|
||||
|
||||
func TestSimulate_10op_10p(t *testing.T) { testSimulate(t, 10, 10) }
|
||||
func TestSimulate_100op_10p(t *testing.T) { testSimulate(t, 100, 10) }
|
||||
func TestSimulate_1000op_10p(t *testing.T) { testSimulate(t, 1000, 10) }
|
||||
func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, 10000, 10) }
|
||||
|
||||
func TestSimulate_100op_100p(t *testing.T) { testSimulate(t, 100, 100) }
|
||||
func TestSimulate_1000op_100p(t *testing.T) { testSimulate(t, 1000, 100) }
|
||||
func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, 10000, 100) }
|
||||
|
||||
func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, 10000, 1000) }
|
||||
|
||||
// Randomly generate operations on a given database with multiple clients to ensure consistency and thread safety.
|
||||
func testSimulate(t *testing.T, threadCount, parallelism int) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
rand.Seed(int64(qseed))
|
||||
|
||||
// A list of operations that readers and writers can perform.
|
||||
var readerHandlers = []simulateHandler{simulateGetHandler}
|
||||
var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler}
|
||||
|
||||
var versions = make(map[int]*QuickDB)
|
||||
versions[1] = NewQuickDB()
|
||||
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
var mutex sync.Mutex
|
||||
|
||||
// Run n threads in parallel, each with their own operation.
|
||||
var wg sync.WaitGroup
|
||||
var threads = make(chan bool, parallelism)
|
||||
var i int
|
||||
for {
|
||||
threads <- true
|
||||
wg.Add(1)
|
||||
writable := ((rand.Int() % 100) < 20) // 20% writers
|
||||
|
||||
// Choose an operation to execute.
|
||||
var handler simulateHandler
|
||||
if writable {
|
||||
handler = writerHandlers[rand.Intn(len(writerHandlers))]
|
||||
} else {
|
||||
handler = readerHandlers[rand.Intn(len(readerHandlers))]
|
||||
}
|
||||
|
||||
// Execute a thread for the given operation.
|
||||
go func(writable bool, handler simulateHandler) {
|
||||
defer wg.Done()
|
||||
|
||||
// Start transaction.
|
||||
tx, err := db.Begin(writable)
|
||||
if err != nil {
|
||||
t.Fatal("tx begin: ", err)
|
||||
}
|
||||
|
||||
// Obtain current state of the dataset.
|
||||
mutex.Lock()
|
||||
var qdb = versions[tx.ID()]
|
||||
if writable {
|
||||
qdb = versions[tx.ID()-1].Copy()
|
||||
}
|
||||
mutex.Unlock()
|
||||
|
||||
// Make sure we commit/rollback the tx at the end and update the state.
|
||||
if writable {
|
||||
defer func() {
|
||||
mutex.Lock()
|
||||
versions[tx.ID()] = qdb
|
||||
mutex.Unlock()
|
||||
|
||||
ok(t, tx.Commit())
|
||||
}()
|
||||
} else {
|
||||
defer tx.Rollback()
|
||||
}
|
||||
|
||||
// Ignore operation if we don't have data yet.
|
||||
if qdb == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Execute handler.
|
||||
handler(tx, qdb)
|
||||
|
||||
// Release a thread back to the scheduling loop.
|
||||
<-threads
|
||||
}(writable, handler)
|
||||
|
||||
i++
|
||||
if i > threadCount {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until all threads are done.
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
type simulateHandler func(tx *bolt.Tx, qdb *QuickDB)
|
||||
|
||||
// Retrieves a key from the database and verifies that it is what is expected.
|
||||
func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) {
|
||||
// Randomly retrieve an existing exist.
|
||||
keys := qdb.Rand()
|
||||
if len(keys) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve root bucket.
|
||||
b := tx.Bucket(keys[0])
|
||||
if b == nil {
|
||||
panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4)))
|
||||
}
|
||||
|
||||
// Drill into nested buckets.
|
||||
for _, key := range keys[1 : len(keys)-1] {
|
||||
b = b.Bucket(key)
|
||||
if b == nil {
|
||||
panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key))
|
||||
}
|
||||
}
|
||||
|
||||
// Verify key/value on the final bucket.
|
||||
expected := qdb.Get(keys)
|
||||
actual := b.Get(keys[len(keys)-1])
|
||||
if !bytes.Equal(actual, expected) {
|
||||
fmt.Println("=== EXPECTED ===")
|
||||
fmt.Println(expected)
|
||||
fmt.Println("=== ACTUAL ===")
|
||||
fmt.Println(actual)
|
||||
fmt.Println("=== END ===")
|
||||
panic("value mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts a key into the database.
|
||||
func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) {
|
||||
var err error
|
||||
keys, value := randKeys(), randValue()
|
||||
|
||||
// Retrieve root bucket.
|
||||
b := tx.Bucket(keys[0])
|
||||
if b == nil {
|
||||
b, err = tx.CreateBucket(keys[0])
|
||||
if err != nil {
|
||||
panic("create bucket: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Create nested buckets, if necessary.
|
||||
for _, key := range keys[1 : len(keys)-1] {
|
||||
child := b.Bucket(key)
|
||||
if child != nil {
|
||||
b = child
|
||||
} else {
|
||||
b, err = b.CreateBucket(key)
|
||||
if err != nil {
|
||||
panic("create bucket: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into database.
|
||||
if err := b.Put(keys[len(keys)-1], value); err != nil {
|
||||
panic("put: " + err.Error())
|
||||
}
|
||||
|
||||
// Insert into in-memory database.
|
||||
qdb.Put(keys, value)
|
||||
}
|
||||
|
||||
// QuickDB is an in-memory database that replicates the functionality of the
|
||||
// Bolt DB type except that it is entirely in-memory. It is meant for testing
|
||||
// that the Bolt database is consistent.
|
||||
type QuickDB struct {
|
||||
sync.RWMutex
|
||||
m map[string]interface{}
|
||||
}
|
||||
|
||||
// NewQuickDB returns an instance of QuickDB.
|
||||
func NewQuickDB() *QuickDB {
|
||||
return &QuickDB{m: make(map[string]interface{})}
|
||||
}
|
||||
|
||||
// Get retrieves the value at a key path.
|
||||
func (db *QuickDB) Get(keys [][]byte) []byte {
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
|
||||
m := db.m
|
||||
for _, key := range keys[:len(keys)-1] {
|
||||
value := m[string(key)]
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
switch value := value.(type) {
|
||||
case map[string]interface{}:
|
||||
m = value
|
||||
case []byte:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Only return if it's a simple value.
|
||||
if value, ok := m[string(keys[len(keys)-1])].([]byte); ok {
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put inserts a value into a key path.
|
||||
func (db *QuickDB) Put(keys [][]byte, value []byte) {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
// Build buckets all the way down the key path.
|
||||
m := db.m
|
||||
for _, key := range keys[:len(keys)-1] {
|
||||
if _, ok := m[string(key)].([]byte); ok {
|
||||
return // Keypath intersects with a simple value. Do nothing.
|
||||
}
|
||||
|
||||
if m[string(key)] == nil {
|
||||
m[string(key)] = make(map[string]interface{})
|
||||
}
|
||||
m = m[string(key)].(map[string]interface{})
|
||||
}
|
||||
|
||||
// Insert value into the last key.
|
||||
m[string(keys[len(keys)-1])] = value
|
||||
}
|
||||
|
||||
// Rand returns a random key path that points to a simple value.
|
||||
func (db *QuickDB) Rand() [][]byte {
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
if len(db.m) == 0 {
|
||||
return nil
|
||||
}
|
||||
var keys [][]byte
|
||||
db.rand(db.m, &keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) {
|
||||
i, index := 0, rand.Intn(len(m))
|
||||
for k, v := range m {
|
||||
if i == index {
|
||||
*keys = append(*keys, []byte(k))
|
||||
if v, ok := v.(map[string]interface{}); ok {
|
||||
db.rand(v, keys)
|
||||
}
|
||||
return
|
||||
}
|
||||
i++
|
||||
}
|
||||
panic("quickdb rand: out-of-range")
|
||||
}
|
||||
|
||||
// Copy copies the entire database.
|
||||
func (db *QuickDB) Copy() *QuickDB {
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
return &QuickDB{m: db.copy(db.m)}
|
||||
}
|
||||
|
||||
func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} {
|
||||
clone := make(map[string]interface{}, len(m))
|
||||
for k, v := range m {
|
||||
switch v := v.(type) {
|
||||
case map[string]interface{}:
|
||||
clone[k] = db.copy(v)
|
||||
default:
|
||||
clone[k] = v
|
||||
}
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func randKey() []byte {
|
||||
var min, max = 1, 1024
|
||||
n := rand.Intn(max-min) + min
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
b[i] = byte(rand.Intn(255))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func randKeys() [][]byte {
|
||||
var keys [][]byte
|
||||
var count = rand.Intn(2) + 2
|
||||
for i := 0; i < count; i++ {
|
||||
keys = append(keys, randKey())
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func randValue() []byte {
|
||||
n := rand.Intn(8192)
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
b[i] = byte(rand.Intn(255))
|
||||
}
|
||||
return b
|
||||
}
|
93
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/tx.go
generated
vendored
93
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/tx.go
generated
vendored
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -29,6 +30,14 @@ type Tx struct {
|
|||
pages map[pgid]*page
|
||||
stats TxStats
|
||||
commitHandlers []func()
|
||||
|
||||
// WriteFlag specifies the flag for write-related methods like WriteTo().
|
||||
// Tx opens the database file with the specified flag to copy the data.
|
||||
//
|
||||
// By default, the flag is unset, which works well for mostly in-memory
|
||||
// workloads. For databases that are much larger than available RAM,
|
||||
// set the flag to syscall.O_DIRECT to avoid trashing the page cache.
|
||||
WriteFlag int
|
||||
}
|
||||
|
||||
// init initializes the transaction.
|
||||
|
@ -87,18 +96,21 @@ func (tx *Tx) Stats() TxStats {
|
|||
|
||||
// Bucket retrieves a bucket by name.
|
||||
// Returns nil if the bucket does not exist.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (tx *Tx) Bucket(name []byte) *Bucket {
|
||||
return tx.root.Bucket(name)
|
||||
}
|
||||
|
||||
// CreateBucket creates a new bucket.
|
||||
// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) {
|
||||
return tx.root.CreateBucket(name)
|
||||
}
|
||||
|
||||
// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
|
||||
// Returns an error if the bucket name is blank, or if the bucket name is too long.
|
||||
// The bucket instance is only valid for the lifetime of the transaction.
|
||||
func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) {
|
||||
return tx.root.CreateBucketIfNotExists(name)
|
||||
}
|
||||
|
@ -157,6 +169,8 @@ func (tx *Tx) Commit() error {
|
|||
// Free the old root bucket.
|
||||
tx.meta.root.root = tx.root.root
|
||||
|
||||
opgid := tx.meta.pgid
|
||||
|
||||
// Free the freelist and allocate new pages for it. This will overestimate
|
||||
// the size of the freelist but not underestimate the size (which would be bad).
|
||||
tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist))
|
||||
|
@ -171,6 +185,14 @@ func (tx *Tx) Commit() error {
|
|||
}
|
||||
tx.meta.freelist = p.id
|
||||
|
||||
// If the high water mark has moved up then attempt to grow the database.
|
||||
if tx.meta.pgid > opgid {
|
||||
if err := tx.db.grow(int(tx.meta.pgid+1) * tx.db.pageSize); err != nil {
|
||||
tx.rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Write dirty pages to disk.
|
||||
startTime = time.Now()
|
||||
if err := tx.write(); err != nil {
|
||||
|
@ -181,8 +203,17 @@ func (tx *Tx) Commit() error {
|
|||
// If strict mode is enabled then perform a consistency check.
|
||||
// Only the first consistency error is reported in the panic.
|
||||
if tx.db.StrictMode {
|
||||
if err, ok := <-tx.Check(); ok {
|
||||
panic("check fail: " + err.Error())
|
||||
ch := tx.Check()
|
||||
var errs []string
|
||||
for {
|
||||
err, ok := <-ch
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
panic("check fail: " + strings.Join(errs, "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +267,8 @@ func (tx *Tx) close() {
|
|||
var freelistPendingN = tx.db.freelist.pending_count()
|
||||
var freelistAlloc = tx.db.freelist.size()
|
||||
|
||||
// Remove writer lock.
|
||||
// Remove transaction ref & writer lock.
|
||||
tx.db.rwtx = nil
|
||||
tx.db.rwlock.Unlock()
|
||||
|
||||
// Merge statistics.
|
||||
|
@ -250,11 +282,16 @@ func (tx *Tx) close() {
|
|||
} else {
|
||||
tx.db.removeTx(tx)
|
||||
}
|
||||
|
||||
// Clear all references.
|
||||
tx.db = nil
|
||||
tx.meta = nil
|
||||
tx.root = Bucket{tx: tx}
|
||||
tx.pages = nil
|
||||
}
|
||||
|
||||
// Copy writes the entire database to a writer.
|
||||
// This function exists for backwards compatibility. Use WriteTo() in
|
||||
// This function exists for backwards compatibility. Use WriteTo() instead.
|
||||
func (tx *Tx) Copy(w io.Writer) error {
|
||||
_, err := tx.WriteTo(w)
|
||||
return err
|
||||
|
@ -263,29 +300,47 @@ func (tx *Tx) Copy(w io.Writer) error {
|
|||
// WriteTo writes the entire database to a writer.
|
||||
// If err == nil then exactly tx.Size() bytes will be written into the writer.
|
||||
func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
|
||||
// Attempt to open reader directly.
|
||||
var f *os.File
|
||||
if f, err = os.OpenFile(tx.db.path, os.O_RDONLY|odirect, 0); err != nil {
|
||||
// Fallback to a regular open if that doesn't work.
|
||||
if f, err = os.OpenFile(tx.db.path, os.O_RDONLY, 0); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Attempt to open reader with WriteFlag
|
||||
f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
// Generate a meta page. We use the same page data for both meta pages.
|
||||
buf := make([]byte, tx.db.pageSize)
|
||||
page := (*page)(unsafe.Pointer(&buf[0]))
|
||||
page.flags = metaPageFlag
|
||||
*page.meta() = *tx.meta
|
||||
|
||||
// Write meta 0.
|
||||
page.id = 0
|
||||
page.meta().checksum = page.meta().sum64()
|
||||
nn, err := w.Write(buf)
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
return n, fmt.Errorf("meta 0 copy: %s", err)
|
||||
}
|
||||
|
||||
// Copy the meta pages.
|
||||
tx.db.metalock.Lock()
|
||||
n, err = io.CopyN(w, f, int64(tx.db.pageSize*2))
|
||||
tx.db.metalock.Unlock()
|
||||
// Write meta 1 with a lower transaction id.
|
||||
page.id = 1
|
||||
page.meta().txid -= 1
|
||||
page.meta().checksum = page.meta().sum64()
|
||||
nn, err = w.Write(buf)
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
return n, fmt.Errorf("meta copy: %s", err)
|
||||
return n, fmt.Errorf("meta 1 copy: %s", err)
|
||||
}
|
||||
|
||||
// Move past the meta pages in the file.
|
||||
if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil {
|
||||
return n, fmt.Errorf("seek: %s", err)
|
||||
}
|
||||
|
||||
// Copy data pages.
|
||||
wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2))
|
||||
n += wn
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
return n, err
|
||||
}
|
||||
|
||||
|
@ -492,7 +547,7 @@ func (tx *Tx) writeMeta() error {
|
|||
}
|
||||
|
||||
// page returns a reference to the page with a given id.
|
||||
// If page has been written to then a temporary bufferred page is returned.
|
||||
// If page has been written to then a temporary buffered page is returned.
|
||||
func (tx *Tx) page(id pgid) *page {
|
||||
// Check the dirty pages first.
|
||||
if tx.pages != nil {
|
||||
|
|
456
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/tx_test.go
generated
vendored
456
libnetwork/Godeps/_workspace/src/github.com/boltdb/bolt/tx_test.go
generated
vendored
|
@ -1,456 +0,0 @@
|
|||
package bolt_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// Ensure that committing a closed transaction returns an error.
|
||||
func TestTx_Commit_Closed(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, _ := db.Begin(true)
|
||||
tx.CreateBucket([]byte("foo"))
|
||||
ok(t, tx.Commit())
|
||||
equals(t, tx.Commit(), bolt.ErrTxClosed)
|
||||
}
|
||||
|
||||
// Ensure that rolling back a closed transaction returns an error.
|
||||
func TestTx_Rollback_Closed(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, _ := db.Begin(true)
|
||||
ok(t, tx.Rollback())
|
||||
equals(t, tx.Rollback(), bolt.ErrTxClosed)
|
||||
}
|
||||
|
||||
// Ensure that committing a read-only transaction returns an error.
|
||||
func TestTx_Commit_ReadOnly(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, _ := db.Begin(false)
|
||||
equals(t, tx.Commit(), bolt.ErrTxNotWritable)
|
||||
}
|
||||
|
||||
// Ensure that a transaction can retrieve a cursor on the root bucket.
|
||||
func TestTx_Cursor(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.CreateBucket([]byte("woojits"))
|
||||
c := tx.Cursor()
|
||||
|
||||
k, v := c.First()
|
||||
equals(t, "widgets", string(k))
|
||||
assert(t, v == nil, "")
|
||||
|
||||
k, v = c.Next()
|
||||
equals(t, "woojits", string(k))
|
||||
assert(t, v == nil, "")
|
||||
|
||||
k, v = c.Next()
|
||||
assert(t, k == nil, "")
|
||||
assert(t, v == nil, "")
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that creating a bucket with a read-only transaction returns an error.
|
||||
func TestTx_CreateBucket_ReadOnly(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("foo"))
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrTxNotWritable, err)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that creating a bucket on a closed transaction returns an error.
|
||||
func TestTx_CreateBucket_Closed(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, _ := db.Begin(true)
|
||||
tx.Commit()
|
||||
b, err := tx.CreateBucket([]byte("foo"))
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrTxClosed, err)
|
||||
}
|
||||
|
||||
// Ensure that a Tx can retrieve a bucket.
|
||||
func TestTx_Bucket(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a Tx retrieving a non-existent key returns nil.
|
||||
func TestTx_Get_Missing(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
value := tx.Bucket([]byte("widgets")).Get([]byte("no_such_key"))
|
||||
assert(t, value == nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can be created and retrieved.
|
||||
func TestTx_CreateBucket(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
// Create a bucket.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
ok(t, err)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Read the bucket through a separate transaction.
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can be created if it doesn't already exist.
|
||||
func TestTx_CreateBucketIfNotExists(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
ok(t, err)
|
||||
|
||||
b, err = tx.CreateBucketIfNotExists([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
ok(t, err)
|
||||
|
||||
b, err = tx.CreateBucketIfNotExists([]byte{})
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrBucketNameRequired, err)
|
||||
|
||||
b, err = tx.CreateBucketIfNotExists(nil)
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrBucketNameRequired, err)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Read the bucket through a separate transaction.
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket cannot be created twice.
|
||||
func TestTx_CreateBucket_Exists(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
// Create a bucket.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
ok(t, err)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Create the same bucket again.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrBucketExists, err)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket is created with a non-blank name.
|
||||
func TestTx_CreateBucket_NameRequired(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := tx.CreateBucket(nil)
|
||||
assert(t, b == nil, "")
|
||||
equals(t, bolt.ErrBucketNameRequired, err)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can be deleted.
|
||||
func TestTx_DeleteBucket(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
|
||||
// Create a bucket and add a value.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
return nil
|
||||
})
|
||||
|
||||
// Delete the bucket and make sure we can't get the value.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
ok(t, tx.DeleteBucket([]byte("widgets")))
|
||||
assert(t, tx.Bucket([]byte("widgets")) == nil, "")
|
||||
return nil
|
||||
})
|
||||
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
// Create the bucket again and make sure there's not a phantom value.
|
||||
b, err := tx.CreateBucket([]byte("widgets"))
|
||||
assert(t, b != nil, "")
|
||||
ok(t, err)
|
||||
assert(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")) == nil, "")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that deleting a bucket on a closed transaction returns an error.
|
||||
func TestTx_DeleteBucket_Closed(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
tx, _ := db.Begin(true)
|
||||
tx.Commit()
|
||||
equals(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxClosed)
|
||||
}
|
||||
|
||||
// Ensure that deleting a bucket with a read-only transaction returns an error.
|
||||
func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
equals(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxNotWritable)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that nothing happens when deleting a bucket that doesn't exist.
|
||||
func TestTx_DeleteBucket_NotFound(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
equals(t, bolt.ErrBucketNotFound, tx.DeleteBucket([]byte("widgets")))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that no error is returned when a tx.ForEach function does not return
|
||||
// an error.
|
||||
func TestTx_ForEach_NoError(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
|
||||
equals(t, nil, tx.ForEach(func(name []byte, b *bolt.Bucket) error {
|
||||
return nil
|
||||
}))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when a tx.ForEach function returns an error.
|
||||
func TestTx_ForEach_WithError(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
|
||||
err := errors.New("foo")
|
||||
equals(t, err, tx.ForEach(func(name []byte, b *bolt.Bucket) error {
|
||||
return err
|
||||
}))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that Tx commit handlers are called after a transaction successfully commits.
|
||||
func TestTx_OnCommit(t *testing.T) {
|
||||
var x int
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.OnCommit(func() { x += 1 })
|
||||
tx.OnCommit(func() { x += 2 })
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
equals(t, 3, x)
|
||||
}
|
||||
|
||||
// Ensure that Tx commit handlers are NOT called after a transaction rolls back.
|
||||
func TestTx_OnCommit_Rollback(t *testing.T) {
|
||||
var x int
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.OnCommit(func() { x += 1 })
|
||||
tx.OnCommit(func() { x += 2 })
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
return errors.New("rollback this commit")
|
||||
})
|
||||
equals(t, 0, x)
|
||||
}
|
||||
|
||||
// Ensure that the database can be copied to a file path.
|
||||
func TestTx_CopyFile(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
var dest = tempfile()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
|
||||
return nil
|
||||
})
|
||||
|
||||
ok(t, db.View(func(tx *bolt.Tx) error { return tx.CopyFile(dest, 0600) }))
|
||||
|
||||
db2, err := bolt.Open(dest, 0600, nil)
|
||||
ok(t, err)
|
||||
defer db2.Close()
|
||||
|
||||
db2.View(func(tx *bolt.Tx) error {
|
||||
equals(t, []byte("bar"), tx.Bucket([]byte("widgets")).Get([]byte("foo")))
|
||||
equals(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz")))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
type failWriterError struct{}
|
||||
|
||||
func (failWriterError) Error() string {
|
||||
return "error injected for tests"
|
||||
}
|
||||
|
||||
type failWriter struct {
|
||||
// fail after this many bytes
|
||||
After int
|
||||
}
|
||||
|
||||
func (f *failWriter) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
if n > f.After {
|
||||
n = f.After
|
||||
err = failWriterError{}
|
||||
}
|
||||
f.After -= n
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Ensure that Copy handles write errors right.
|
||||
func TestTx_CopyFile_Error_Meta(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
|
||||
return nil
|
||||
})
|
||||
|
||||
err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{}) })
|
||||
equals(t, err.Error(), "meta copy: error injected for tests")
|
||||
}
|
||||
|
||||
// Ensure that Copy handles write errors right.
|
||||
func TestTx_CopyFile_Error_Normal(t *testing.T) {
|
||||
db := NewTestDB()
|
||||
defer db.Close()
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
|
||||
return nil
|
||||
})
|
||||
|
||||
err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{3 * db.Info().PageSize}) })
|
||||
equals(t, err.Error(), "error injected for tests")
|
||||
}
|
||||
|
||||
func ExampleTx_Rollback() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Create a bucket.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
return err
|
||||
})
|
||||
|
||||
// Set a value for a key.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
})
|
||||
|
||||
// Update the key but rollback the transaction so it never saves.
|
||||
tx, _ := db.Begin(true)
|
||||
b := tx.Bucket([]byte("widgets"))
|
||||
b.Put([]byte("foo"), []byte("baz"))
|
||||
tx.Rollback()
|
||||
|
||||
// Ensure that our original value is still set.
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
|
||||
fmt.Printf("The value for 'foo' is still: %s\n", value)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// The value for 'foo' is still: bar
|
||||
}
|
||||
|
||||
func ExampleTx_CopyFile() {
|
||||
// Open the database.
|
||||
db, _ := bolt.Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
// Create a bucket and a key.
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.CreateBucket([]byte("widgets"))
|
||||
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
|
||||
return nil
|
||||
})
|
||||
|
||||
// Copy the database to another file.
|
||||
toFile := tempfile()
|
||||
db.View(func(tx *bolt.Tx) error { return tx.CopyFile(toFile, 0666) })
|
||||
defer os.Remove(toFile)
|
||||
|
||||
// Open the cloned database.
|
||||
db2, _ := bolt.Open(toFile, 0666, nil)
|
||||
defer db2.Close()
|
||||
|
||||
// Ensure that the key exists in the copy.
|
||||
db2.View(func(tx *bolt.Tx) error {
|
||||
value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
|
||||
fmt.Printf("The value for 'foo' in the clone is: %s\n", value)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Output:
|
||||
// The value for 'foo' in the clone is: bar
|
||||
}
|
867
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
867
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
|
@ -1,867 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func ExampleApp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--name", "Jeremy"}
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Action = func(c *Context) {
|
||||
fmt.Printf("Hello %v\n", c.String("name"))
|
||||
}
|
||||
app.Author = "Harrison"
|
||||
app.Email = "harrison@lolwut.com"
|
||||
app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppSubcommand() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
||||
app := NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "hello",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []Command{
|
||||
{
|
||||
Name: "english",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []Flag{
|
||||
StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
fmt.Println("Hello,", c.String("name"))
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello, Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppHelp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "h", "describeit"}
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// NAME:
|
||||
// describeit - use it to see a description
|
||||
//
|
||||
// USAGE:
|
||||
// command describeit [arguments...]
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// This is how we describe describeit the function
|
||||
}
|
||||
|
||||
func ExampleAppBashComplete() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--generate-bash-completion"}
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "greet"
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
}, {
|
||||
Name: "next",
|
||||
Usage: "next example",
|
||||
Description: "more stuff to see when generating bash completion",
|
||||
Action: func(c *Context) {
|
||||
fmt.Printf("the next example")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// describeit
|
||||
// d
|
||||
// next
|
||||
// help
|
||||
// h
|
||||
}
|
||||
|
||||
func TestApp_Run(t *testing.T) {
|
||||
s := ""
|
||||
|
||||
app := NewApp()
|
||||
app.Action = func(c *Context) {
|
||||
s = s + c.Args().First()
|
||||
}
|
||||
|
||||
err := app.Run([]string{"command", "foo"})
|
||||
expect(t, err, nil)
|
||||
err = app.Run([]string{"command", "bar"})
|
||||
expect(t, err, nil)
|
||||
expect(t, s, "foobar")
|
||||
}
|
||||
|
||||
var commandAppTests = []struct {
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{"foobar", true},
|
||||
{"batbaz", true},
|
||||
{"b", true},
|
||||
{"f", true},
|
||||
{"bat", false},
|
||||
{"nothing", false},
|
||||
}
|
||||
|
||||
func TestApp_Command(t *testing.T) {
|
||||
app := NewApp()
|
||||
fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
|
||||
batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
|
||||
app.Commands = []Command{
|
||||
fooCommand,
|
||||
batCommand,
|
||||
}
|
||||
|
||||
for _, test := range commandAppTests {
|
||||
expect(t, app.Command(test.name) != nil, test.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
|
||||
app := NewApp()
|
||||
command := Command{
|
||||
Name: "cmd",
|
||||
Flags: []Flag{
|
||||
StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
|
||||
|
||||
expect(t, parsedOption, "my-option")
|
||||
expect(t, firstArg, "my-arg")
|
||||
}
|
||||
|
||||
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
||||
var context *Context
|
||||
|
||||
a := NewApp()
|
||||
a.Commands = []Command{
|
||||
{
|
||||
Name: "foo",
|
||||
Action: func(c *Context) {
|
||||
context = c
|
||||
},
|
||||
Flags: []Flag{
|
||||
StringFlag{
|
||||
Name: "lang",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
},
|
||||
Before: func(_ *Context) error { return nil },
|
||||
},
|
||||
}
|
||||
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
|
||||
|
||||
expect(t, context.Args().Get(0), "abcd")
|
||||
expect(t, context.String("lang"), "spanish")
|
||||
}
|
||||
|
||||
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
||||
var parsedOption string
|
||||
var args []string
|
||||
|
||||
app := NewApp()
|
||||
command := Command{
|
||||
Name: "cmd",
|
||||
Flags: []Flag{
|
||||
StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
parsedOption = c.String("option")
|
||||
args = c.Args()
|
||||
},
|
||||
}
|
||||
app.Commands = []Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
|
||||
|
||||
expect(t, parsedOption, "my-option")
|
||||
expect(t, args[0], "my-arg")
|
||||
expect(t, args[1], "--")
|
||||
expect(t, args[2], "--notARealFlag")
|
||||
}
|
||||
|
||||
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
|
||||
var args []string
|
||||
|
||||
app := NewApp()
|
||||
command := Command{
|
||||
Name: "cmd",
|
||||
Action: func(c *Context) {
|
||||
args = c.Args()
|
||||
},
|
||||
}
|
||||
app.Commands = []Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
|
||||
|
||||
expect(t, args[0], "my-arg")
|
||||
expect(t, args[1], "--")
|
||||
expect(t, args[2], "notAFlagAtAll")
|
||||
}
|
||||
|
||||
func TestApp_Float64Flag(t *testing.T) {
|
||||
var meters float64
|
||||
|
||||
app := NewApp()
|
||||
app.Flags = []Flag{
|
||||
Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
||||
}
|
||||
app.Action = func(c *Context) {
|
||||
meters = c.Float64("height")
|
||||
}
|
||||
|
||||
app.Run([]string{"", "--height", "1.93"})
|
||||
expect(t, meters, 1.93)
|
||||
}
|
||||
|
||||
func TestApp_ParseSliceFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
var parsedIntSlice []int
|
||||
var parsedStringSlice []string
|
||||
|
||||
app := NewApp()
|
||||
command := Command{
|
||||
Name: "cmd",
|
||||
Flags: []Flag{
|
||||
IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
|
||||
StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
parsedIntSlice = c.IntSlice("p")
|
||||
parsedStringSlice = c.StringSlice("ip")
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
|
||||
|
||||
IntsEquals := func(a, b []int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
StrsEquals := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
var expectedIntSlice = []int{22, 80}
|
||||
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
|
||||
|
||||
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
|
||||
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
|
||||
}
|
||||
|
||||
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
|
||||
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
|
||||
var parsedIntSlice []int
|
||||
var parsedStringSlice []string
|
||||
|
||||
app := NewApp()
|
||||
command := Command{
|
||||
Name: "cmd",
|
||||
Flags: []Flag{
|
||||
IntSliceFlag{Name: "a", Usage: "set numbers"},
|
||||
StringSliceFlag{Name: "str", Usage: "set strings"},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
parsedIntSlice = c.IntSlice("a")
|
||||
parsedStringSlice = c.StringSlice("str")
|
||||
},
|
||||
}
|
||||
app.Commands = []Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
|
||||
|
||||
var expectedIntSlice = []int{2}
|
||||
var expectedStringSlice = []string{"A"}
|
||||
|
||||
if parsedIntSlice[0] != expectedIntSlice[0] {
|
||||
t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
|
||||
}
|
||||
|
||||
if parsedStringSlice[0] != expectedStringSlice[0] {
|
||||
t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_DefaultStdout(t *testing.T) {
|
||||
app := NewApp()
|
||||
|
||||
if app.Writer != os.Stdout {
|
||||
t.Error("Default output writer not set.")
|
||||
}
|
||||
}
|
||||
|
||||
type mockWriter struct {
|
||||
written []byte
|
||||
}
|
||||
|
||||
func (fw *mockWriter) Write(p []byte) (n int, err error) {
|
||||
if fw.written == nil {
|
||||
fw.written = p
|
||||
} else {
|
||||
fw.written = append(fw.written, p...)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (fw *mockWriter) GetWritten() (b []byte) {
|
||||
return fw.written
|
||||
}
|
||||
|
||||
func TestApp_SetStdout(t *testing.T) {
|
||||
w := &mockWriter{}
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "test"
|
||||
app.Writer = w
|
||||
|
||||
err := app.Run([]string{"help"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if len(w.written) == 0 {
|
||||
t.Error("App did not write output to desired writer.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_BeforeFunc(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
beforeError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := NewApp()
|
||||
|
||||
app.Before = func(c *Context) error {
|
||||
beforeRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return beforeError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []Command{
|
||||
Command{
|
||||
Name: "sub",
|
||||
Action: func(c *Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the Before() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
beforeRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != beforeError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == true {
|
||||
t.Errorf("Subcommand executed when NOT expected")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestApp_AfterFunc(t *testing.T) {
|
||||
afterRun, subcommandRun := false, false
|
||||
afterError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := NewApp()
|
||||
|
||||
app.After = func(c *Context) error {
|
||||
afterRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return afterError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []Command{
|
||||
Command{
|
||||
Name: "sub",
|
||||
Action: func(c *Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the After() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
afterRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != afterError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppNoHelpFlag(t *testing.T) {
|
||||
oldFlag := HelpFlag
|
||||
defer func() {
|
||||
HelpFlag = oldFlag
|
||||
}()
|
||||
|
||||
HelpFlag = BoolFlag{}
|
||||
|
||||
app := NewApp()
|
||||
err := app.Run([]string{"test", "-h"})
|
||||
|
||||
if err != flag.ErrHelp {
|
||||
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppHelpPrinter(t *testing.T) {
|
||||
oldPrinter := HelpPrinter
|
||||
defer func() {
|
||||
HelpPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
HelpPrinter = func(w io.Writer, template string, data interface{}) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := NewApp()
|
||||
app.Run([]string{"-h"})
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Help printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppVersionPrinter(t *testing.T) {
|
||||
oldPrinter := VersionPrinter
|
||||
defer func() {
|
||||
VersionPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
VersionPrinter = func(c *Context) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := NewApp()
|
||||
ctx := NewContext(app, nil, nil)
|
||||
ShowVersion(ctx)
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Version printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCommandNotFound(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
app := NewApp()
|
||||
|
||||
app.CommandNotFound = func(c *Context, command string) {
|
||||
beforeRun = true
|
||||
}
|
||||
|
||||
app.Commands = []Command{
|
||||
Command{
|
||||
Name: "bar",
|
||||
Action: func(c *Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "foo"})
|
||||
|
||||
expect(t, beforeRun, true)
|
||||
expect(t, subcommandRun, false)
|
||||
}
|
||||
|
||||
func TestGlobalFlag(t *testing.T) {
|
||||
var globalFlag string
|
||||
var globalFlagSet bool
|
||||
app := NewApp()
|
||||
app.Flags = []Flag{
|
||||
StringFlag{Name: "global, g", Usage: "global"},
|
||||
}
|
||||
app.Action = func(c *Context) {
|
||||
globalFlag = c.GlobalString("global")
|
||||
globalFlagSet = c.GlobalIsSet("global")
|
||||
}
|
||||
app.Run([]string{"command", "-g", "foo"})
|
||||
expect(t, globalFlag, "foo")
|
||||
expect(t, globalFlagSet, true)
|
||||
|
||||
}
|
||||
|
||||
func TestGlobalFlagsInSubcommands(t *testing.T) {
|
||||
subcommandRun := false
|
||||
parentFlag := false
|
||||
app := NewApp()
|
||||
|
||||
app.Flags = []Flag{
|
||||
BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
||||
}
|
||||
|
||||
app.Commands = []Command{
|
||||
Command{
|
||||
Name: "foo",
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "parent, p", Usage: "Parent flag"},
|
||||
},
|
||||
Subcommands: []Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Action: func(c *Context) {
|
||||
if c.GlobalBool("debug") {
|
||||
subcommandRun = true
|
||||
}
|
||||
if c.GlobalBool("parent") {
|
||||
parentFlag = true
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "-d", "foo", "-p", "bar"})
|
||||
|
||||
expect(t, subcommandRun, true)
|
||||
expect(t, parentFlag, true)
|
||||
}
|
||||
|
||||
func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
|
||||
var subcommandHelpTopics = [][]string{
|
||||
{"command", "foo", "--help"},
|
||||
{"command", "foo", "-h"},
|
||||
{"command", "foo", "help"},
|
||||
}
|
||||
|
||||
for _, flagSet := range subcommandHelpTopics {
|
||||
t.Logf("==> checking with flags %v", flagSet)
|
||||
|
||||
app := NewApp()
|
||||
buf := new(bytes.Buffer)
|
||||
app.Writer = buf
|
||||
|
||||
subCmdBar := Command{
|
||||
Name: "bar",
|
||||
Usage: "does bar things",
|
||||
}
|
||||
subCmdBaz := Command{
|
||||
Name: "baz",
|
||||
Usage: "does baz things",
|
||||
}
|
||||
cmd := Command{
|
||||
Name: "foo",
|
||||
Description: "descriptive wall of text about how it does foo things",
|
||||
Subcommands: []Command{subCmdBar, subCmdBaz},
|
||||
}
|
||||
|
||||
app.Commands = []Command{cmd}
|
||||
err := app.Run(flagSet)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
t.Logf("output: %q\n", buf.Bytes())
|
||||
|
||||
if strings.Contains(output, "No help topic for") {
|
||||
t.Errorf("expect a help topic, got none: \n%q", output)
|
||||
}
|
||||
|
||||
for _, shouldContain := range []string{
|
||||
cmd.Name, cmd.Description,
|
||||
subCmdBar.Name, subCmdBar.Usage,
|
||||
subCmdBaz.Name, subCmdBaz.Usage,
|
||||
} {
|
||||
if !strings.Contains(output, shouldContain) {
|
||||
t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_Run_SubcommandFullPath(t *testing.T) {
|
||||
app := NewApp()
|
||||
buf := new(bytes.Buffer)
|
||||
app.Writer = buf
|
||||
|
||||
subCmd := Command{
|
||||
Name: "bar",
|
||||
Usage: "does bar things",
|
||||
}
|
||||
cmd := Command{
|
||||
Name: "foo",
|
||||
Description: "foo commands",
|
||||
Subcommands: []Command{subCmd},
|
||||
}
|
||||
app.Commands = []Command{cmd}
|
||||
|
||||
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
if !strings.Contains(output, "foo bar - does bar things") {
|
||||
t.Errorf("expected full path to subcommand: %s", output)
|
||||
}
|
||||
if !strings.Contains(output, "command foo bar [arguments...]") {
|
||||
t.Errorf("expected full path to subcommand: %s", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_Run_Help(t *testing.T) {
|
||||
var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
|
||||
|
||||
for _, args := range helpArguments {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
t.Logf("==> checking with arguments %v", args)
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "boom"
|
||||
app.Usage = "make an explosive entrance"
|
||||
app.Writer = buf
|
||||
app.Action = func(c *Context) {
|
||||
buf.WriteString("boom I say!")
|
||||
}
|
||||
|
||||
err := app.Run(args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
t.Logf("output: %q\n", buf.Bytes())
|
||||
|
||||
if !strings.Contains(output, "boom - make an explosive entrance") {
|
||||
t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_Run_Version(t *testing.T) {
|
||||
var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
|
||||
|
||||
for _, args := range versionArguments {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
t.Logf("==> checking with arguments %v", args)
|
||||
|
||||
app := NewApp()
|
||||
app.Name = "boom"
|
||||
app.Usage = "make an explosive entrance"
|
||||
app.Version = "0.1.0"
|
||||
app.Writer = buf
|
||||
app.Action = func(c *Context) {
|
||||
buf.WriteString("boom I say!")
|
||||
}
|
||||
|
||||
err := app.Run(args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
t.Logf("output: %q\n", buf.Bytes())
|
||||
|
||||
if !strings.Contains(output, "0.1.0") {
|
||||
t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||
app := NewApp()
|
||||
app.Action = func(c *Context) {}
|
||||
app.Before = func(c *Context) error { return fmt.Errorf("before error") }
|
||||
app.After = func(c *Context) error { return fmt.Errorf("after error") }
|
||||
|
||||
err := app.Run([]string{"foo"})
|
||||
if err == nil {
|
||||
t.Fatalf("expected to recieve error from Run, got none")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "before error") {
|
||||
t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "after error") {
|
||||
t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||
app := NewApp()
|
||||
app.Commands = []Command{
|
||||
Command{
|
||||
Name: "bar",
|
||||
Before: func(c *Context) error { return fmt.Errorf("before error") },
|
||||
After: func(c *Context) error { return fmt.Errorf("after error") },
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"foo", "bar"})
|
||||
if err == nil {
|
||||
t.Fatalf("expected to recieve error from Run, got none")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "before error") {
|
||||
t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "after error") {
|
||||
t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#! /bin/bash
|
||||
|
||||
: ${PROG:=$(basename ${BASH_SOURCE})}
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
local cur prev opts base
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _cli_bash_autocomplete $PROG
|
|
@ -1,5 +0,0 @@
|
|||
autoload -U compinit && compinit
|
||||
autoload -U bashcompinit && bashcompinit
|
||||
|
||||
script_dir=$(dirname $0)
|
||||
source ${script_dir}/bash_autocomplete
|
98
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
98
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
|
@ -1,98 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
app := NewApp()
|
||||
app.Name = "todo"
|
||||
app.Usage = "task list on the command line"
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
|
||||
func ExampleSubcommand() {
|
||||
app := NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []Command{
|
||||
{
|
||||
Name: "hello",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []Command{
|
||||
{
|
||||
Name: "english",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []Flag{
|
||||
StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
println("Hello, ", c.String("name"))
|
||||
},
|
||||
}, {
|
||||
Name: "spanish",
|
||||
Aliases: []string{"sp"},
|
||||
Usage: "sends a greeting in spanish",
|
||||
Flags: []Flag{
|
||||
StringFlag{
|
||||
Name: "surname",
|
||||
Value: "Jones",
|
||||
Usage: "Surname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
println("Hola, ", c.String("surname"))
|
||||
},
|
||||
}, {
|
||||
Name: "french",
|
||||
Aliases: []string{"fr"},
|
||||
Usage: "sends a greeting in french",
|
||||
Flags: []Flag{
|
||||
StringFlag{
|
||||
Name: "nickname",
|
||||
Value: "Stevie",
|
||||
Usage: "Nickname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *Context) {
|
||||
println("Bonjour, ", c.String("nickname"))
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "bye",
|
||||
Usage: "says goodbye",
|
||||
Action: func(c *Context) {
|
||||
println("bye")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
47
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
47
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
|
@ -1,47 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommandDoNotIgnoreFlags(t *testing.T) {
|
||||
app := NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"blah", "blah", "-break"}
|
||||
set.Parse(test)
|
||||
|
||||
c := NewContext(app, set, nil)
|
||||
|
||||
command := Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *Context) {},
|
||||
}
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err.Error(), "flag provided but not defined: -break")
|
||||
}
|
||||
|
||||
func TestCommandIgnoreFlags(t *testing.T) {
|
||||
app := NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"blah", "blah"}
|
||||
set.Parse(test)
|
||||
|
||||
c := NewContext(app, set, nil)
|
||||
|
||||
command := Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *Context) {},
|
||||
SkipFlagParsing: true,
|
||||
}
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
113
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
113
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
|
@ -1,113 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewContext(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Int("myflag", 42, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
command := Command{Name: "mycommand"}
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
c.Command = command
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
expect(t, c.GlobalInt("myflag"), 42)
|
||||
expect(t, c.Command.Name, "mycommand")
|
||||
}
|
||||
|
||||
func TestContext_Int(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
}
|
||||
|
||||
func TestContext_Duration(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Duration("myflag", time.Duration(12*time.Second), "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
|
||||
}
|
||||
|
||||
func TestContext_String(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("myflag", "hello world", "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.String("myflag"), "hello world")
|
||||
}
|
||||
|
||||
func TestContext_Bool(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.Bool("myflag"), false)
|
||||
}
|
||||
|
||||
func TestContext_BoolT(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", true, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
expect(t, c.BoolT("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_Args(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := NewContext(nil, set, nil)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
expect(t, len(c.Args()), 2)
|
||||
expect(t, c.Bool("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_IsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.IsSet("myflag"), true)
|
||||
expect(t, c.IsSet("otherflag"), false)
|
||||
expect(t, c.IsSet("bogusflag"), false)
|
||||
expect(t, c.IsSet("myflagGlobal"), false)
|
||||
}
|
||||
|
||||
func TestContext_GlobalIsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalSet.Bool("myflagGlobalUnset", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.GlobalIsSet("myflag"), false)
|
||||
expect(t, c.GlobalIsSet("otherflag"), false)
|
||||
expect(t, c.GlobalIsSet("bogusflag"), false)
|
||||
expect(t, c.GlobalIsSet("myflagGlobal"), true)
|
||||
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
|
||||
expect(t, c.GlobalIsSet("bogusGlobal"), false)
|
||||
}
|
||||
|
||||
func TestContext_NumFlags(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalCtx := NewContext(nil, globalSet, nil)
|
||||
c := NewContext(nil, set, globalCtx)
|
||||
set.Parse([]string{"--myflag", "--otherflag=foo"})
|
||||
globalSet.Parse([]string{"--myflagGlobal"})
|
||||
expect(t, c.NumFlags(), 2)
|
||||
}
|
740
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
generated
vendored
740
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
generated
vendored
|
@ -1,740 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var boolFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help\t"},
|
||||
{"h", "-h\t"},
|
||||
}
|
||||
|
||||
func TestBoolFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range boolFlagTests {
|
||||
flag := BoolFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stringFlagTests = []struct {
|
||||
name string
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{"help", "", "--help \t"},
|
||||
{"h", "", "-h \t"},
|
||||
{"h", "", "-h \t"},
|
||||
{"test", "Something", "--test \"Something\"\t"},
|
||||
}
|
||||
|
||||
func TestStringFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range stringFlagTests {
|
||||
flag := StringFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_FOO", "derp")
|
||||
for _, test := range stringFlagTests {
|
||||
flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_FOO]") {
|
||||
t.Errorf("%s does not end with [$APP_FOO]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stringSliceFlagTests = []struct {
|
||||
name string
|
||||
value *StringSlice
|
||||
expected string
|
||||
}{
|
||||
{"help", func() *StringSlice {
|
||||
s := &StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "--help [--help option --help option]\t"},
|
||||
{"h", func() *StringSlice {
|
||||
s := &StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "-h [-h option -h option]\t"},
|
||||
{"h", func() *StringSlice {
|
||||
s := &StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "-h [-h option -h option]\t"},
|
||||
{"test", func() *StringSlice {
|
||||
s := &StringSlice{}
|
||||
s.Set("Something")
|
||||
return s
|
||||
}(), "--test [--test option --test option]\t"},
|
||||
}
|
||||
|
||||
func TestStringSliceFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range stringSliceFlagTests {
|
||||
flag := StringSliceFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_QWWX", "11,4")
|
||||
for _, test := range stringSliceFlagTests {
|
||||
flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_QWWX]") {
|
||||
t.Errorf("%q does not end with [$APP_QWWX]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestIntFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range intFlagTests {
|
||||
flag := IntFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAR", "2")
|
||||
for _, test := range intFlagTests {
|
||||
flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAR]") {
|
||||
t.Errorf("%s does not end with [$APP_BAR]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var durationFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestDurationFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range durationFlagTests {
|
||||
flag := DurationFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAR", "2h3m6s")
|
||||
for _, test := range durationFlagTests {
|
||||
flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAR]") {
|
||||
t.Errorf("%s does not end with [$APP_BAR]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intSliceFlagTests = []struct {
|
||||
name string
|
||||
value *IntSlice
|
||||
expected string
|
||||
}{
|
||||
{"help", &IntSlice{}, "--help [--help option --help option]\t"},
|
||||
{"h", &IntSlice{}, "-h [-h option -h option]\t"},
|
||||
{"h", &IntSlice{}, "-h [-h option -h option]\t"},
|
||||
{"test", func() *IntSlice {
|
||||
i := &IntSlice{}
|
||||
i.Set("9")
|
||||
return i
|
||||
}(), "--test [--test option --test option]\t"},
|
||||
}
|
||||
|
||||
func TestIntSliceFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range intSliceFlagTests {
|
||||
flag := IntSliceFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_SMURF", "42,3")
|
||||
for _, test := range intSliceFlagTests {
|
||||
flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_SMURF]") {
|
||||
t.Errorf("%q does not end with [$APP_SMURF]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var float64FlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestFloat64FlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range float64FlagTests {
|
||||
flag := Float64Flag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAZ", "99.4")
|
||||
for _, test := range float64FlagTests {
|
||||
flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAZ]") {
|
||||
t.Errorf("%s does not end with [$APP_BAZ]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var genericFlagTests = []struct {
|
||||
name string
|
||||
value Generic
|
||||
expected string
|
||||
}{
|
||||
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
|
||||
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
|
||||
}
|
||||
|
||||
func TestGenericFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range genericFlagTests {
|
||||
flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_ZAP", "3")
|
||||
for _, test := range genericFlagTests {
|
||||
flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_ZAP]") {
|
||||
t.Errorf("%s does not end with [$APP_ZAP]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMultiString(t *testing.T) {
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.String("serve") != "10" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("s") != "10" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_COUNT", "20")
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.String("count") != "20" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("c") != "20" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_COUNT", "20")
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.String("count") != "20" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("c") != "20" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSlice(t *testing.T) {
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringSliceFlag{Name: "serve, s", Value: &StringSlice{}},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSliceFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiInt(t *testing.T) {
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
IntFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Int("serve") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("s") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Int("timeout") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("t") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Int("timeout") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("t") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSlice(t *testing.T) {
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
IntSliceFlag{Name: "serve, s", Value: &IntSlice{}},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSliceFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&App{
|
||||
Flags: []Flag{
|
||||
IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64(t *testing.T) {
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
Float64Flag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Float64("serve") != 10.2 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("s") != 10.2 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10.2"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64FromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Float64("timeout") != 15.5 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("t") != 15.5 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Float64("timeout") != 15.5 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("t") != 15.5 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBool(t *testing.T) {
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Bool("serve") != true {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Bool("s") != true {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "--serve"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "1")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Bool("debug") != true {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.Bool("d") != true {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "1")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.Bool("debug") != true {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.Bool("d") != true {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolT(t *testing.T) {
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolTFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.BoolT("serve") != true {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.BoolT("s") != true {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "--serve"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolTFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "0")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.BoolT("debug") != false {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.BoolT("d") != false {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "0")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if ctx.BoolT("debug") != false {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.BoolT("d") != false {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
type Parser [2]string
|
||||
|
||||
func (p *Parser) Set(value string) error {
|
||||
parts := strings.Split(value, ",")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
(*p)[0] = parts[0]
|
||||
(*p)[1] = parts[1]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) String() string {
|
||||
return fmt.Sprintf("%s,%s", p[0], p[1])
|
||||
}
|
||||
|
||||
func TestParseGeneric(t *testing.T) {
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
GenericFlag{Name: "serve, s", Value: &Parser{}},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10,20"})
|
||||
}
|
||||
|
||||
func TestParseGenericFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_SERVE", "20,30")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseGenericFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_FOO", "99,2000")
|
||||
a := App{
|
||||
Flags: []Flag{
|
||||
GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
|
||||
},
|
||||
Action: func(ctx *Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
|
||||
t.Errorf("value not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
36
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go
generated
vendored
36
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_ShowAppHelp_NoAuthor(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := NewApp()
|
||||
app.Writer = output
|
||||
|
||||
c := NewContext(app, nil, nil)
|
||||
|
||||
ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ShowAppHelp_NoVersion(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := NewApp()
|
||||
app.Writer = output
|
||||
|
||||
app.Version = ""
|
||||
|
||||
c := NewContext(app, nil, nil)
|
||||
|
||||
ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
|
||||
}
|
||||
}
|
19
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
generated
vendored
19
libnetwork/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/* Test Helpers */
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
if a != b {
|
||||
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
if a == b {
|
||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
202
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/LICENSE
generated
vendored
Normal file
202
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://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
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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
|
||||
|
||||
http://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.
|
5
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/NOTICE
generated
vendored
Normal file
5
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/NOTICE
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
CoreOS Project
|
||||
Copyright 2014 CoreOS, Inc
|
||||
|
||||
This product includes software developed at CoreOS, Inc.
|
||||
(http://www.coreos.com/).
|
896
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/client_test.go
generated
vendored
896
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/client_test.go
generated
vendored
|
@ -1,896 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type actionAssertingHTTPClient struct {
|
||||
t *testing.T
|
||||
num int
|
||||
act httpAction
|
||||
|
||||
resp http.Response
|
||||
body []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (a *actionAssertingHTTPClient) Do(_ context.Context, act httpAction) (*http.Response, []byte, error) {
|
||||
if !reflect.DeepEqual(a.act, act) {
|
||||
a.t.Errorf("#%d: unexpected httpAction: want=%#v got=%#v", a.num, a.act, act)
|
||||
}
|
||||
|
||||
return &a.resp, a.body, a.err
|
||||
}
|
||||
|
||||
type staticHTTPClient struct {
|
||||
resp http.Response
|
||||
body []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *staticHTTPClient) Do(context.Context, httpAction) (*http.Response, []byte, error) {
|
||||
return &s.resp, s.body, s.err
|
||||
}
|
||||
|
||||
type staticHTTPAction struct {
|
||||
request http.Request
|
||||
}
|
||||
|
||||
func (s *staticHTTPAction) HTTPRequest(url.URL) *http.Request {
|
||||
return &s.request
|
||||
}
|
||||
|
||||
type staticHTTPResponse struct {
|
||||
resp http.Response
|
||||
body []byte
|
||||
err error
|
||||
}
|
||||
|
||||
type multiStaticHTTPClient struct {
|
||||
responses []staticHTTPResponse
|
||||
cur int
|
||||
}
|
||||
|
||||
func (s *multiStaticHTTPClient) Do(context.Context, httpAction) (*http.Response, []byte, error) {
|
||||
r := s.responses[s.cur]
|
||||
s.cur++
|
||||
return &r.resp, r.body, r.err
|
||||
}
|
||||
|
||||
func newStaticHTTPClientFactory(responses []staticHTTPResponse) httpClientFactory {
|
||||
var cur int
|
||||
return func(url.URL) httpClient {
|
||||
r := responses[cur]
|
||||
cur++
|
||||
return &staticHTTPClient{resp: r.resp, body: r.body, err: r.err}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeTransport struct {
|
||||
respchan chan *http.Response
|
||||
errchan chan error
|
||||
startCancel chan struct{}
|
||||
finishCancel chan struct{}
|
||||
}
|
||||
|
||||
func newFakeTransport() *fakeTransport {
|
||||
return &fakeTransport{
|
||||
respchan: make(chan *http.Response, 1),
|
||||
errchan: make(chan error, 1),
|
||||
startCancel: make(chan struct{}, 1),
|
||||
finishCancel: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *fakeTransport) CancelRequest(*http.Request) {
|
||||
t.startCancel <- struct{}{}
|
||||
}
|
||||
|
||||
type fakeAction struct{}
|
||||
|
||||
func (a *fakeAction) HTTPRequest(url.URL) *http.Request {
|
||||
return &http.Request{}
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoSuccess(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
tr.respchan <- &http.Response{
|
||||
StatusCode: http.StatusTeapot,
|
||||
Body: ioutil.NopCloser(strings.NewReader("foo")),
|
||||
}
|
||||
|
||||
resp, body, err := c.Do(context.Background(), &fakeAction{})
|
||||
if err != nil {
|
||||
t.Fatalf("incorrect error value: want=nil got=%v", err)
|
||||
}
|
||||
|
||||
wantCode := http.StatusTeapot
|
||||
if wantCode != resp.StatusCode {
|
||||
t.Fatalf("invalid response code: want=%d got=%d", wantCode, resp.StatusCode)
|
||||
}
|
||||
|
||||
wantBody := []byte("foo")
|
||||
if !reflect.DeepEqual(wantBody, body) {
|
||||
t.Fatalf("invalid response body: want=%q got=%q", wantBody, body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoError(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
tr.errchan <- errors.New("fixture")
|
||||
|
||||
_, _, err := c.Do(context.Background(), &fakeAction{})
|
||||
if err == nil {
|
||||
t.Fatalf("expected non-nil error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoCancelContext(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
tr.startCancel <- struct{}{}
|
||||
tr.finishCancel <- struct{}{}
|
||||
|
||||
_, _, err := c.Do(context.Background(), &fakeAction{})
|
||||
if err == nil {
|
||||
t.Fatalf("expected non-nil error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
type checkableReadCloser struct {
|
||||
io.ReadCloser
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (c *checkableReadCloser) Close() error {
|
||||
if !c.closed {
|
||||
c.closed = true
|
||||
return c.ReadCloser.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoCancelContextResponseBodyClosed(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
// create an already-cancelled context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
body := &checkableReadCloser{ReadCloser: ioutil.NopCloser(strings.NewReader("foo"))}
|
||||
go func() {
|
||||
// wait that simpleHTTPClient knows the context is already timed out,
|
||||
// and calls CancelRequest
|
||||
testutil.WaitSchedule()
|
||||
|
||||
// response is returned before cancel effects
|
||||
tr.respchan <- &http.Response{Body: body}
|
||||
}()
|
||||
|
||||
_, _, err := c.Do(ctx, &fakeAction{})
|
||||
if err == nil {
|
||||
t.Fatalf("expected non-nil error, got nil")
|
||||
}
|
||||
|
||||
if !body.closed {
|
||||
t.Fatalf("expected closed body")
|
||||
}
|
||||
}
|
||||
|
||||
type blockingBody struct {
|
||||
c chan struct{}
|
||||
}
|
||||
|
||||
func (bb *blockingBody) Read(p []byte) (n int, err error) {
|
||||
<-bb.c
|
||||
return 0, errors.New("closed")
|
||||
}
|
||||
|
||||
func (bb *blockingBody) Close() error {
|
||||
close(bb.c)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoCancelContextResponseBodyClosedWithBlockingBody(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
body := &checkableReadCloser{ReadCloser: &blockingBody{c: make(chan struct{})}}
|
||||
go func() {
|
||||
tr.respchan <- &http.Response{Body: body}
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
// cancel after the body is received
|
||||
cancel()
|
||||
}()
|
||||
|
||||
_, _, err := c.Do(ctx, &fakeAction{})
|
||||
if err != context.Canceled {
|
||||
t.Fatalf("expected %+v, got %+v", context.Canceled, err)
|
||||
}
|
||||
|
||||
if !body.closed {
|
||||
t.Fatalf("expected closed body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
c := &simpleHTTPClient{transport: tr}
|
||||
|
||||
donechan := make(chan struct{})
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
c.Do(ctx, &fakeAction{})
|
||||
close(donechan)
|
||||
}()
|
||||
|
||||
// This should call CancelRequest and begin the cancellation process
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-donechan:
|
||||
t.Fatalf("simpleHTTPClient.Do should not have exited yet")
|
||||
default:
|
||||
}
|
||||
|
||||
tr.finishCancel <- struct{}{}
|
||||
|
||||
select {
|
||||
case <-donechan:
|
||||
//expected behavior
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("simpleHTTPClient.Do did not exit within 1s")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleHTTPClientDoHeaderTimeout(t *testing.T) {
|
||||
tr := newFakeTransport()
|
||||
tr.finishCancel <- struct{}{}
|
||||
c := &simpleHTTPClient{transport: tr, headerTimeout: time.Millisecond}
|
||||
|
||||
errc := make(chan error)
|
||||
go func() {
|
||||
_, _, err := c.Do(context.Background(), &fakeAction{})
|
||||
errc <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errc:
|
||||
if err == nil {
|
||||
t.Fatalf("expected non-nil error, got nil")
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("unexpected timeout when waitting for the test to finish")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientDo(t *testing.T) {
|
||||
fakeErr := errors.New("fake!")
|
||||
fakeURL := url.URL{}
|
||||
tests := []struct {
|
||||
client *httpClusterClient
|
||||
wantCode int
|
||||
wantErr error
|
||||
wantPinned int
|
||||
}{
|
||||
// first good response short-circuits Do
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{fakeURL, fakeURL},
|
||||
clientFactory: newStaticHTTPClientFactory(
|
||||
[]staticHTTPResponse{
|
||||
{resp: http.Response{StatusCode: http.StatusTeapot}},
|
||||
{err: fakeErr},
|
||||
},
|
||||
),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
},
|
||||
|
||||
// fall through to good endpoint if err is arbitrary
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{fakeURL, fakeURL},
|
||||
clientFactory: newStaticHTTPClientFactory(
|
||||
[]staticHTTPResponse{
|
||||
{err: fakeErr},
|
||||
{resp: http.Response{StatusCode: http.StatusTeapot}},
|
||||
},
|
||||
),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
wantPinned: 1,
|
||||
},
|
||||
|
||||
// context.Canceled short-circuits Do
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{fakeURL, fakeURL},
|
||||
clientFactory: newStaticHTTPClientFactory(
|
||||
[]staticHTTPResponse{
|
||||
{err: context.Canceled},
|
||||
{resp: http.Response{StatusCode: http.StatusTeapot}},
|
||||
},
|
||||
),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantErr: context.Canceled,
|
||||
},
|
||||
|
||||
// return err if there are no endpoints
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{},
|
||||
clientFactory: newHTTPClientFactory(nil, nil, 0),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantErr: ErrNoEndpoints,
|
||||
},
|
||||
|
||||
// return err if all endpoints return arbitrary errors
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{fakeURL, fakeURL},
|
||||
clientFactory: newStaticHTTPClientFactory(
|
||||
[]staticHTTPResponse{
|
||||
{err: fakeErr},
|
||||
{err: fakeErr},
|
||||
},
|
||||
),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantErr: &ClusterError{Errors: []error{fakeErr, fakeErr}},
|
||||
},
|
||||
|
||||
// 500-level errors cause Do to fallthrough to next endpoint
|
||||
{
|
||||
client: &httpClusterClient{
|
||||
endpoints: []url.URL{fakeURL, fakeURL},
|
||||
clientFactory: newStaticHTTPClientFactory(
|
||||
[]staticHTTPResponse{
|
||||
{resp: http.Response{StatusCode: http.StatusBadGateway}},
|
||||
{resp: http.Response{StatusCode: http.StatusTeapot}},
|
||||
},
|
||||
),
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
wantPinned: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
resp, _, err := tt.client.Do(context.Background(), nil)
|
||||
if !reflect.DeepEqual(tt.wantErr, err) {
|
||||
t.Errorf("#%d: got err=%v, want=%v", i, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
if tt.wantCode != 0 {
|
||||
t.Errorf("#%d: resp is nil, want=%d", i, tt.wantCode)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.StatusCode != tt.wantCode {
|
||||
t.Errorf("#%d: resp code=%d, want=%d", i, resp.StatusCode, tt.wantCode)
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.client.pinned != tt.wantPinned {
|
||||
t.Errorf("#%d: pinned=%d, want=%d", i, tt.client.pinned, tt.wantPinned)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientDoDeadlineExceedContext(t *testing.T) {
|
||||
fakeURL := url.URL{}
|
||||
tr := newFakeTransport()
|
||||
tr.finishCancel <- struct{}{}
|
||||
c := &httpClusterClient{
|
||||
clientFactory: newHTTPClientFactory(tr, DefaultCheckRedirect, 0),
|
||||
endpoints: []url.URL{fakeURL},
|
||||
}
|
||||
|
||||
errc := make(chan error)
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
|
||||
defer cancel()
|
||||
_, _, err := c.Do(ctx, &fakeAction{})
|
||||
errc <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errc:
|
||||
if err != context.DeadlineExceeded {
|
||||
t.Errorf("err = %+v, want %+v", err, context.DeadlineExceeded)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("unexpected timeout when waitting for request to deadline exceed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirectedHTTPAction(t *testing.T) {
|
||||
act := &redirectedHTTPAction{
|
||||
action: &staticHTTPAction{
|
||||
request: http.Request{
|
||||
Method: "DELETE",
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "foo.example.com",
|
||||
Path: "/ping",
|
||||
},
|
||||
},
|
||||
},
|
||||
location: url.URL{
|
||||
Scheme: "https",
|
||||
Host: "bar.example.com",
|
||||
Path: "/pong",
|
||||
},
|
||||
}
|
||||
|
||||
want := &http.Request{
|
||||
Method: "DELETE",
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "bar.example.com",
|
||||
Path: "/pong",
|
||||
},
|
||||
}
|
||||
got := act.HTTPRequest(url.URL{Scheme: "http", Host: "baz.example.com", Path: "/pang"})
|
||||
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("HTTPRequest is %#v, want %#v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirectFollowingHTTPClient(t *testing.T) {
|
||||
tests := []struct {
|
||||
checkRedirect CheckRedirectFunc
|
||||
client httpClient
|
||||
wantCode int
|
||||
wantErr error
|
||||
}{
|
||||
// errors bubbled up
|
||||
{
|
||||
checkRedirect: func(int) error { return ErrTooManyRedirects },
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
err: errors.New("fail!"),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: errors.New("fail!"),
|
||||
},
|
||||
|
||||
// no need to follow redirect if none given
|
||||
{
|
||||
checkRedirect: func(int) error { return ErrTooManyRedirects },
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTeapot,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
},
|
||||
|
||||
// redirects if less than max
|
||||
{
|
||||
checkRedirect: func(via int) error {
|
||||
if via >= 2 {
|
||||
return ErrTooManyRedirects
|
||||
}
|
||||
return nil
|
||||
},
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTeapot,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
},
|
||||
|
||||
// succeed after reaching max redirects
|
||||
{
|
||||
checkRedirect: func(via int) error {
|
||||
if via >= 3 {
|
||||
return ErrTooManyRedirects
|
||||
}
|
||||
return nil
|
||||
},
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTeapot,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCode: http.StatusTeapot,
|
||||
},
|
||||
|
||||
// fail if too many redirects
|
||||
{
|
||||
checkRedirect: func(via int) error {
|
||||
if via >= 2 {
|
||||
return ErrTooManyRedirects
|
||||
}
|
||||
return nil
|
||||
},
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTeapot,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: ErrTooManyRedirects,
|
||||
},
|
||||
|
||||
// fail if Location header not set
|
||||
{
|
||||
checkRedirect: func(int) error { return ErrTooManyRedirects },
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: errors.New("Location header not set"),
|
||||
},
|
||||
|
||||
// fail if Location header is invalid
|
||||
{
|
||||
checkRedirect: func(int) error { return ErrTooManyRedirects },
|
||||
client: &multiStaticHTTPClient{
|
||||
responses: []staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{":"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: errors.New("Location header not valid URL: :"),
|
||||
},
|
||||
|
||||
// fail if redirects checked way too many times
|
||||
{
|
||||
checkRedirect: func(int) error { return nil },
|
||||
client: &staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Header: http.Header{"Location": []string{"http://example.com"}},
|
||||
},
|
||||
},
|
||||
wantErr: errTooManyRedirectChecks,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
client := &redirectFollowingHTTPClient{client: tt.client, checkRedirect: tt.checkRedirect}
|
||||
resp, _, err := client.Do(context.Background(), nil)
|
||||
if !reflect.DeepEqual(tt.wantErr, err) {
|
||||
t.Errorf("#%d: got err=%v, want=%v", i, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
if tt.wantCode != 0 {
|
||||
t.Errorf("#%d: resp is nil, want=%d", i, tt.wantCode)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.StatusCode != tt.wantCode {
|
||||
t.Errorf("#%d: resp code=%d, want=%d", i, resp.StatusCode, tt.wantCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultCheckRedirect(t *testing.T) {
|
||||
tests := []struct {
|
||||
num int
|
||||
err error
|
||||
}{
|
||||
{0, nil},
|
||||
{5, nil},
|
||||
{10, nil},
|
||||
{11, ErrTooManyRedirects},
|
||||
{29, ErrTooManyRedirects},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
err := DefaultCheckRedirect(tt.num)
|
||||
if !reflect.DeepEqual(tt.err, err) {
|
||||
t.Errorf("#%d: want=%#v got=%#v", i, tt.err, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientSync(t *testing.T) {
|
||||
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}},
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
})
|
||||
|
||||
hc := &httpClusterClient{
|
||||
clientFactory: cf,
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
}
|
||||
err := hc.reset([]string{"http://127.0.0.1:2379"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during setup: %#v", err)
|
||||
}
|
||||
|
||||
want := []string{"http://127.0.0.1:2379"}
|
||||
got := hc.Endpoints()
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("incorrect endpoints: want=%#v got=%#v", want, got)
|
||||
}
|
||||
|
||||
err = hc.Sync(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during Sync: %#v", err)
|
||||
}
|
||||
|
||||
want = []string{"http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002", "http://127.0.0.1:4003"}
|
||||
got = hc.Endpoints()
|
||||
sort.Sort(sort.StringSlice(got))
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("incorrect endpoints post-Sync: want=%#v got=%#v", want, got)
|
||||
}
|
||||
|
||||
err = hc.reset([]string{"http://127.0.0.1:4009"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during reset: %#v", err)
|
||||
}
|
||||
|
||||
want = []string{"http://127.0.0.1:4009"}
|
||||
got = hc.Endpoints()
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("incorrect endpoints post-reset: want=%#v got=%#v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientSyncFail(t *testing.T) {
|
||||
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
|
||||
{err: errors.New("fail!")},
|
||||
})
|
||||
|
||||
hc := &httpClusterClient{
|
||||
clientFactory: cf,
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
}
|
||||
err := hc.reset([]string{"http://127.0.0.1:2379"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during setup: %#v", err)
|
||||
}
|
||||
|
||||
want := []string{"http://127.0.0.1:2379"}
|
||||
got := hc.Endpoints()
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("incorrect endpoints: want=%#v got=%#v", want, got)
|
||||
}
|
||||
|
||||
err = hc.Sync(context.Background())
|
||||
if err == nil {
|
||||
t.Fatalf("got nil error during Sync")
|
||||
}
|
||||
|
||||
got = hc.Endpoints()
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("incorrect endpoints after failed Sync: want=%#v got=%#v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientAutoSyncCancelContext(t *testing.T) {
|
||||
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}},
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
})
|
||||
|
||||
hc := &httpClusterClient{
|
||||
clientFactory: cf,
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
}
|
||||
err := hc.reset([]string{"http://127.0.0.1:2379"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during setup: %#v", err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
err = hc.AutoSync(ctx, time.Hour)
|
||||
if err != context.Canceled {
|
||||
t.Fatalf("incorrect error value: want=%v got=%v", context.Canceled, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientAutoSyncFail(t *testing.T) {
|
||||
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
|
||||
{err: errors.New("fail!")},
|
||||
})
|
||||
|
||||
hc := &httpClusterClient{
|
||||
clientFactory: cf,
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
}
|
||||
err := hc.reset([]string{"http://127.0.0.1:2379"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during setup: %#v", err)
|
||||
}
|
||||
|
||||
err = hc.AutoSync(context.Background(), time.Hour)
|
||||
if err.Error() != ErrClusterUnavailable.Error() {
|
||||
t.Fatalf("incorrect error value: want=%v got=%v", ErrClusterUnavailable, err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTTPClusterClientSyncPinEndpoint tests that Sync() pins the endpoint when
|
||||
// it gets the exactly same member list as before.
|
||||
func TestHTTPClusterClientSyncPinEndpoint(t *testing.T) {
|
||||
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
|
||||
{
|
||||
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}},
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
{
|
||||
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}},
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
{
|
||||
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}},
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
})
|
||||
|
||||
hc := &httpClusterClient{
|
||||
clientFactory: cf,
|
||||
rand: rand.New(rand.NewSource(0)),
|
||||
}
|
||||
err := hc.reset([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error during setup: %#v", err)
|
||||
}
|
||||
pinnedEndpoint := hc.endpoints[hc.pinned]
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
err = hc.Sync(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: unexpected error during Sync: %#v", i, err)
|
||||
}
|
||||
|
||||
if g := hc.endpoints[hc.pinned]; g != pinnedEndpoint {
|
||||
t.Errorf("#%d: pinned endpoint = %s, want %s", i, g, pinnedEndpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientResetFail(t *testing.T) {
|
||||
tests := [][]string{
|
||||
// need at least one endpoint
|
||||
{},
|
||||
|
||||
// urls must be valid
|
||||
{":"},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
hc := &httpClusterClient{rand: rand.New(rand.NewSource(0))}
|
||||
err := hc.reset(tt)
|
||||
if err == nil {
|
||||
t.Errorf("#%d: expected non-nil error", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientResetPinRandom(t *testing.T) {
|
||||
round := 2000
|
||||
pinNum := 0
|
||||
for i := 0; i < round; i++ {
|
||||
hc := &httpClusterClient{rand: rand.New(rand.NewSource(int64(i)))}
|
||||
err := hc.reset([]string{"http://127.0.0.1:4001", "http://127.0.0.1:4002", "http://127.0.0.1:4003"})
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: reset error (%v)", i, err)
|
||||
}
|
||||
if hc.endpoints[hc.pinned].String() == "http://127.0.0.1:4001" {
|
||||
pinNum++
|
||||
}
|
||||
}
|
||||
|
||||
min := 1.0/3.0 - 0.05
|
||||
max := 1.0/3.0 + 0.05
|
||||
if ratio := float64(pinNum) / float64(round); ratio > max || ratio < min {
|
||||
t.Errorf("pinned ratio = %v, want [%v, %v]", ratio, min, max)
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
// +build !go1.5
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
select {
|
||||
case resp := <-t.respchan:
|
||||
return resp, nil
|
||||
case err := <-t.errchan:
|
||||
return nil, err
|
||||
case <-t.startCancel:
|
||||
select {
|
||||
// this simulates that the request is finished before cancel effects
|
||||
case resp := <-t.respchan:
|
||||
return resp, nil
|
||||
// wait on finishCancel to simulate taking some amount of
|
||||
// time while calling CancelRequest
|
||||
case <-t.finishCancel:
|
||||
return nil, errors.New("cancelled")
|
||||
}
|
||||
}
|
||||
}
|
42
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/fake_transport_test.go
generated
vendored
42
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/fake_transport_test.go
generated
vendored
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
// +build go1.5
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
select {
|
||||
case resp := <-t.respchan:
|
||||
return resp, nil
|
||||
case err := <-t.errchan:
|
||||
return nil, err
|
||||
case <-t.startCancel:
|
||||
case <-req.Cancel:
|
||||
}
|
||||
select {
|
||||
// this simulates that the request is finished before cancel effects
|
||||
case resp := <-t.respchan:
|
||||
return resp, nil
|
||||
// wait on finishCancel to simulate taking some amount of
|
||||
// time while calling CancelRequest
|
||||
case <-t.finishCancel:
|
||||
return nil, errors.New("cancelled")
|
||||
}
|
||||
}
|
73
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/keys_bench_test.go
generated
vendored
73
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/keys_bench_test.go
generated
vendored
|
@ -1,73 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func createTestNode(size int) *Node {
|
||||
return &Node{
|
||||
Key: strings.Repeat("a", 30),
|
||||
Value: strings.Repeat("a", size),
|
||||
CreatedIndex: 123456,
|
||||
ModifiedIndex: 123456,
|
||||
TTL: 123456789,
|
||||
}
|
||||
}
|
||||
|
||||
func createTestNodeWithChildren(children, size int) *Node {
|
||||
node := createTestNode(size)
|
||||
for i := 0; i < children; i++ {
|
||||
node.Nodes = append(node.Nodes, createTestNode(size))
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func createTestResponse(children, size int) *Response {
|
||||
return &Response{
|
||||
Action: "aaaaa",
|
||||
Node: createTestNodeWithChildren(children, size),
|
||||
PrevNode: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkResponseUnmarshalling(b *testing.B, children, size int) {
|
||||
header := http.Header{}
|
||||
header.Add("X-Etcd-Index", "123456")
|
||||
response := createTestResponse(children, size)
|
||||
body, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
newResponse := new(Response)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if newResponse, err = unmarshalSuccessfulKeysResponse(header, body); err != nil {
|
||||
b.Errorf("error unmarshaling response (%v)", err)
|
||||
}
|
||||
|
||||
}
|
||||
if !reflect.DeepEqual(response.Node, newResponse.Node) {
|
||||
b.Errorf("Unexpected difference in a parsed response: \n%+v\n%+v", response, newResponse)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSmallResponseUnmarshal(b *testing.B) {
|
||||
benchmarkResponseUnmarshalling(b, 30, 20)
|
||||
}
|
||||
|
||||
func BenchmarkManySmallResponseUnmarshal(b *testing.B) {
|
||||
benchmarkResponseUnmarshalling(b, 3000, 20)
|
||||
}
|
||||
|
||||
func BenchmarkMediumResponseUnmarshal(b *testing.B) {
|
||||
benchmarkResponseUnmarshalling(b, 300, 200)
|
||||
}
|
||||
|
||||
func BenchmarkLargeResponseUnmarshal(b *testing.B) {
|
||||
benchmarkResponseUnmarshalling(b, 3000, 2000)
|
||||
}
|
1407
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/keys_test.go
generated
vendored
1407
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/keys_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
522
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/members_test.go
generated
vendored
522
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/members_test.go
generated
vendored
|
@ -1,522 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
)
|
||||
|
||||
func TestMembersAPIActionList(t *testing.T) {
|
||||
ep := url.URL{Scheme: "http", Host: "example.com"}
|
||||
act := &membersAPIActionList{}
|
||||
|
||||
wantURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
Path: "/v2/members",
|
||||
}
|
||||
|
||||
got := *act.HTTPRequest(ep)
|
||||
err := assertRequest(got, "GET", wantURL, http.Header{}, nil)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembersAPIActionAdd(t *testing.T) {
|
||||
ep := url.URL{Scheme: "http", Host: "example.com"}
|
||||
act := &membersAPIActionAdd{
|
||||
peerURLs: types.URLs([]url.URL{
|
||||
{Scheme: "https", Host: "127.0.0.1:8081"},
|
||||
{Scheme: "http", Host: "127.0.0.1:8080"},
|
||||
}),
|
||||
}
|
||||
|
||||
wantURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
Path: "/v2/members",
|
||||
}
|
||||
wantHeader := http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
}
|
||||
wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`)
|
||||
|
||||
got := *act.HTTPRequest(ep)
|
||||
err := assertRequest(got, "POST", wantURL, wantHeader, wantBody)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembersAPIActionUpdate(t *testing.T) {
|
||||
ep := url.URL{Scheme: "http", Host: "example.com"}
|
||||
act := &membersAPIActionUpdate{
|
||||
memberID: "0xabcd",
|
||||
peerURLs: types.URLs([]url.URL{
|
||||
{Scheme: "https", Host: "127.0.0.1:8081"},
|
||||
{Scheme: "http", Host: "127.0.0.1:8080"},
|
||||
}),
|
||||
}
|
||||
|
||||
wantURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
Path: "/v2/members/0xabcd",
|
||||
}
|
||||
wantHeader := http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
}
|
||||
wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`)
|
||||
|
||||
got := *act.HTTPRequest(ep)
|
||||
err := assertRequest(got, "PUT", wantURL, wantHeader, wantBody)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembersAPIActionRemove(t *testing.T) {
|
||||
ep := url.URL{Scheme: "http", Host: "example.com"}
|
||||
act := &membersAPIActionRemove{memberID: "XXX"}
|
||||
|
||||
wantURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
Path: "/v2/members/XXX",
|
||||
}
|
||||
|
||||
got := *act.HTTPRequest(ep)
|
||||
err := assertRequest(got, "DELETE", wantURL, http.Header{}, nil)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssertStatusCode(t *testing.T) {
|
||||
if err := assertStatusCode(404, 400); err == nil {
|
||||
t.Errorf("assertStatusCode failed to detect conflict in 400 vs 404")
|
||||
}
|
||||
|
||||
if err := assertStatusCode(404, 400, 404); err != nil {
|
||||
t.Errorf("assertStatusCode found conflict in (404,400) vs 400: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2MembersURL(t *testing.T) {
|
||||
got := v2MembersURL(url.URL{
|
||||
Scheme: "http",
|
||||
Host: "foo.example.com:4002",
|
||||
Path: "/pants",
|
||||
})
|
||||
want := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "foo.example.com:4002",
|
||||
Path: "/pants/v2/members",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("v2MembersURL got %#v, want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberUnmarshal(t *testing.T) {
|
||||
tests := []struct {
|
||||
body []byte
|
||||
wantMember Member
|
||||
wantError bool
|
||||
}{
|
||||
// no URLs, just check ID & Name
|
||||
{
|
||||
body: []byte(`{"id": "c", "name": "dungarees"}`),
|
||||
wantMember: Member{ID: "c", Name: "dungarees", PeerURLs: nil, ClientURLs: nil},
|
||||
},
|
||||
|
||||
// both client and peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:2379"], "clientURLs": ["http://127.0.0.1:2379"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:2379", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"https://example.com",
|
||||
},
|
||||
ClientURLs: nil,
|
||||
},
|
||||
},
|
||||
|
||||
// multiple client URLs
|
||||
{
|
||||
body: []byte(`{"clientURLs": ["http://127.0.0.1:2379", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: nil,
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"https://example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// invalid JSON
|
||||
{
|
||||
body: []byte(`{"peerU`),
|
||||
wantError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got := Member{}
|
||||
err := json.Unmarshal(tt.body, &got)
|
||||
if tt.wantError != (err != nil) {
|
||||
t.Errorf("#%d: want error %t, got %v", i, tt.wantError, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.wantMember, got) {
|
||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.wantMember, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberCollectionUnmarshalFail(t *testing.T) {
|
||||
mc := &memberCollection{}
|
||||
if err := mc.UnmarshalJSON([]byte(`{`)); err == nil {
|
||||
t.Errorf("got nil error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberCollectionUnmarshal(t *testing.T) {
|
||||
tests := []struct {
|
||||
body []byte
|
||||
want memberCollection
|
||||
}{
|
||||
{
|
||||
body: []byte(`{}`),
|
||||
want: memberCollection([]Member{}),
|
||||
},
|
||||
{
|
||||
body: []byte(`{"members":[]}`),
|
||||
want: memberCollection([]Member{}),
|
||||
},
|
||||
{
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
want: memberCollection(
|
||||
[]Member{
|
||||
{
|
||||
ID: "2745e2525fce8fe",
|
||||
Name: "node3",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:7003",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4003",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "42134f434382925",
|
||||
Name: "node1",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:2380",
|
||||
"http://127.0.0.1:7001",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "94088180e21eb87b",
|
||||
Name: "node2",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:7002",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4002",
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
var got memberCollection
|
||||
err := json.Unmarshal(tt.body, &got)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.want, got) {
|
||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberCreateRequestMarshal(t *testing.T) {
|
||||
req := memberCreateOrUpdateRequest{
|
||||
PeerURLs: types.URLs([]url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:8081"},
|
||||
{Scheme: "https", Host: "127.0.0.1:8080"},
|
||||
}),
|
||||
}
|
||||
want := []byte(`{"peerURLs":["http://127.0.0.1:8081","https://127.0.0.1:8080"]}`)
|
||||
|
||||
got, err := json.Marshal(&req)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal returned unexpected err=%v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("Failed to marshal memberCreateRequest: want=%s, got=%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIAddSuccess(t *testing.T) {
|
||||
wantAction := &membersAPIActionAdd{
|
||||
peerURLs: types.URLs([]url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:7002"},
|
||||
}),
|
||||
}
|
||||
|
||||
mAPI := &httpMembersAPI{
|
||||
client: &actionAssertingHTTPClient{
|
||||
t: t,
|
||||
act: wantAction,
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusCreated,
|
||||
},
|
||||
body: []byte(`{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"]}`),
|
||||
},
|
||||
}
|
||||
|
||||
wantResponseMember := &Member{
|
||||
ID: "94088180e21eb87b",
|
||||
PeerURLs: []string{"http://127.0.0.1:7002"},
|
||||
}
|
||||
|
||||
m, err := mAPI.Add(context.Background(), "http://127.0.0.1:7002")
|
||||
if err != nil {
|
||||
t.Errorf("got non-nil err: %#v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(wantResponseMember, m) {
|
||||
t.Errorf("incorrect Member: want=%#v got=%#v", wantResponseMember, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIAddError(t *testing.T) {
|
||||
okPeer := "http://example.com:2379"
|
||||
tests := []struct {
|
||||
peerURL string
|
||||
client httpClient
|
||||
|
||||
// if wantErr == nil, assert that the returned error is non-nil
|
||||
// if wantErr != nil, assert that the returned error matches
|
||||
wantErr error
|
||||
}{
|
||||
// malformed peer URL
|
||||
{
|
||||
peerURL: ":",
|
||||
},
|
||||
|
||||
// generic httpClient failure
|
||||
{
|
||||
peerURL: okPeer,
|
||||
client: &staticHTTPClient{err: errors.New("fail!")},
|
||||
},
|
||||
|
||||
// unrecognized HTTP status code
|
||||
{
|
||||
peerURL: okPeer,
|
||||
client: &staticHTTPClient{
|
||||
resp: http.Response{StatusCode: http.StatusTeapot},
|
||||
},
|
||||
},
|
||||
|
||||
// unmarshal body into membersError on StatusConflict
|
||||
{
|
||||
peerURL: okPeer,
|
||||
client: &staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusConflict,
|
||||
},
|
||||
body: []byte(`{"message":"fail!"}`),
|
||||
},
|
||||
wantErr: membersError{Message: "fail!"},
|
||||
},
|
||||
|
||||
// fail to unmarshal body on StatusConflict
|
||||
{
|
||||
peerURL: okPeer,
|
||||
client: &staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusConflict,
|
||||
},
|
||||
body: []byte(`{"`),
|
||||
},
|
||||
},
|
||||
|
||||
// fail to unmarshal body on StatusCreated
|
||||
{
|
||||
peerURL: okPeer,
|
||||
client: &staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusCreated,
|
||||
},
|
||||
body: []byte(`{"id":"XX`),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
mAPI := &httpMembersAPI{client: tt.client}
|
||||
m, err := mAPI.Add(context.Background(), tt.peerURL)
|
||||
if err == nil {
|
||||
t.Errorf("#%d: got nil err", i)
|
||||
}
|
||||
if tt.wantErr != nil && !reflect.DeepEqual(tt.wantErr, err) {
|
||||
t.Errorf("#%d: incorrect error: want=%#v got=%#v", i, tt.wantErr, err)
|
||||
}
|
||||
if m != nil {
|
||||
t.Errorf("#%d: got non-nil Member", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIRemoveSuccess(t *testing.T) {
|
||||
wantAction := &membersAPIActionRemove{
|
||||
memberID: "94088180e21eb87b",
|
||||
}
|
||||
|
||||
mAPI := &httpMembersAPI{
|
||||
client: &actionAssertingHTTPClient{
|
||||
t: t,
|
||||
act: wantAction,
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusNoContent,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := mAPI.Remove(context.Background(), "94088180e21eb87b"); err != nil {
|
||||
t.Errorf("got non-nil err: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIRemoveFail(t *testing.T) {
|
||||
tests := []httpClient{
|
||||
// generic error
|
||||
&staticHTTPClient{
|
||||
err: errors.New("fail!"),
|
||||
},
|
||||
|
||||
// unexpected HTTP status code
|
||||
&staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
mAPI := &httpMembersAPI{client: tt}
|
||||
if err := mAPI.Remove(context.Background(), "94088180e21eb87b"); err == nil {
|
||||
t.Errorf("#%d: got nil err", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIListSuccess(t *testing.T) {
|
||||
wantAction := &membersAPIActionList{}
|
||||
mAPI := &httpMembersAPI{
|
||||
client: &actionAssertingHTTPClient{
|
||||
t: t,
|
||||
act: wantAction,
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
},
|
||||
body: []byte(`{"members":[{"id":"94088180e21eb87b","name":"node2","peerURLs":["http://127.0.0.1:7002"],"clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
},
|
||||
}
|
||||
|
||||
wantResponseMembers := []Member{
|
||||
{
|
||||
ID: "94088180e21eb87b",
|
||||
Name: "node2",
|
||||
PeerURLs: []string{"http://127.0.0.1:7002"},
|
||||
ClientURLs: []string{"http://127.0.0.1:4002"},
|
||||
},
|
||||
}
|
||||
|
||||
m, err := mAPI.List(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("got non-nil err: %#v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(wantResponseMembers, m) {
|
||||
t.Errorf("incorrect Members: want=%#v got=%#v", wantResponseMembers, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPMembersAPIListError(t *testing.T) {
|
||||
tests := []httpClient{
|
||||
// generic httpClient failure
|
||||
&staticHTTPClient{err: errors.New("fail!")},
|
||||
|
||||
// unrecognized HTTP status code
|
||||
&staticHTTPClient{
|
||||
resp: http.Response{StatusCode: http.StatusTeapot},
|
||||
},
|
||||
|
||||
// fail to unmarshal body on StatusOK
|
||||
&staticHTTPClient{
|
||||
resp: http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
},
|
||||
body: []byte(`[{"id":"XX`),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
mAPI := &httpMembersAPI{client: tt}
|
||||
ms, err := mAPI.List(context.Background())
|
||||
if err == nil {
|
||||
t.Errorf("#%d: got nil err", i)
|
||||
}
|
||||
if ms != nil {
|
||||
t.Errorf("#%d: got non-nil Member slice", i)
|
||||
}
|
||||
}
|
||||
}
|
102
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/srv_test.go
generated
vendored
102
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/client/srv_test.go
generated
vendored
|
@ -1,102 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSRVDiscover(t *testing.T) {
|
||||
defer func() { lookupSRV = net.LookupSRV }()
|
||||
|
||||
tests := []struct {
|
||||
withSSL []*net.SRV
|
||||
withoutSSL []*net.SRV
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
[]*net.SRV{},
|
||||
[]*net.SRV{},
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
[]*net.SRV{
|
||||
{Target: "10.0.0.1", Port: 2480},
|
||||
{Target: "10.0.0.2", Port: 2480},
|
||||
{Target: "10.0.0.3", Port: 2480},
|
||||
},
|
||||
[]*net.SRV{},
|
||||
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480"},
|
||||
},
|
||||
{
|
||||
[]*net.SRV{
|
||||
{Target: "10.0.0.1", Port: 2480},
|
||||
{Target: "10.0.0.2", Port: 2480},
|
||||
{Target: "10.0.0.3", Port: 2480},
|
||||
},
|
||||
[]*net.SRV{
|
||||
{Target: "10.0.0.1", Port: 7001},
|
||||
},
|
||||
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
|
||||
},
|
||||
{
|
||||
[]*net.SRV{
|
||||
{Target: "10.0.0.1", Port: 2480},
|
||||
{Target: "10.0.0.2", Port: 2480},
|
||||
{Target: "10.0.0.3", Port: 2480},
|
||||
},
|
||||
[]*net.SRV{
|
||||
{Target: "10.0.0.1", Port: 7001},
|
||||
},
|
||||
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
|
||||
},
|
||||
{
|
||||
[]*net.SRV{
|
||||
{Target: "a.example.com", Port: 2480},
|
||||
{Target: "b.example.com", Port: 2480},
|
||||
{Target: "c.example.com", Port: 2480},
|
||||
},
|
||||
[]*net.SRV{},
|
||||
[]string{"https://a.example.com:2480", "https://b.example.com:2480", "https://c.example.com:2480"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
lookupSRV = func(service string, proto string, domain string) (string, []*net.SRV, error) {
|
||||
if service == "etcd-server-ssl" {
|
||||
return "", tt.withSSL, nil
|
||||
}
|
||||
if service == "etcd-server" {
|
||||
return "", tt.withoutSSL, nil
|
||||
}
|
||||
return "", nil, errors.New("Unkown service in mock")
|
||||
}
|
||||
|
||||
d := NewSRVDiscover()
|
||||
|
||||
endpoints, err := d.Discover("example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("%d: err: %#v", i, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(endpoints, tt.expected) {
|
||||
t.Errorf("#%d: endpoints = %v, want %v", i, endpoints, tt.expected)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
38
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/pathutil/path_test.go
generated
vendored
38
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/pathutil/path_test.go
generated
vendored
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package pathutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCanonicalURLPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
p string
|
||||
wp string
|
||||
}{
|
||||
{"/a", "/a"},
|
||||
{"", "/"},
|
||||
{"a", "/a"},
|
||||
{"//a", "/a"},
|
||||
{"/a/.", "/a"},
|
||||
{"/a/..", "/"},
|
||||
{"/a/", "/a/"},
|
||||
{"/a//", "/a/"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if g := CanonicalURLPath(tt.p); g != tt.wp {
|
||||
t.Errorf("#%d: canonical path = %s, want %s", i, g, tt.wp)
|
||||
}
|
||||
}
|
||||
}
|
95
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go
generated
vendored
95
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go
generated
vendored
|
@ -1,95 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIDString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input ID
|
||||
want string
|
||||
}{
|
||||
{
|
||||
input: 12,
|
||||
want: "c",
|
||||
},
|
||||
{
|
||||
input: 4918257920282737594,
|
||||
want: "444129853c343bba",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got := tt.input.String()
|
||||
if tt.want != got {
|
||||
t.Errorf("#%d: ID.String failure: want=%v, got=%v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDFromString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want ID
|
||||
}{
|
||||
{
|
||||
input: "17",
|
||||
want: 23,
|
||||
},
|
||||
{
|
||||
input: "612840dae127353",
|
||||
want: 437557308098245459,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got, err := IDFromString(tt.input)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: IDFromString failure: err=%v", i, err)
|
||||
continue
|
||||
}
|
||||
if tt.want != got {
|
||||
t.Errorf("#%d: IDFromString failure: want=%v, got=%v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDFromStringFail(t *testing.T) {
|
||||
tests := []string{
|
||||
"",
|
||||
"XXX",
|
||||
"612840dae127353612840dae127353",
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
_, err := IDFromString(tt)
|
||||
if err == nil {
|
||||
t.Fatalf("#%d: IDFromString expected error, but err=nil", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDSlice(t *testing.T) {
|
||||
g := []ID{10, 500, 5, 1, 100, 25}
|
||||
w := []ID{1, 5, 10, 25, 100, 500}
|
||||
sort.Sort(IDSlice(g))
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
186
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go
generated
vendored
186
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go
generated
vendored
|
@ -1,186 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnsafeSet(t *testing.T) {
|
||||
driveSetTests(t, NewUnsafeSet())
|
||||
}
|
||||
|
||||
func TestThreadsafeSet(t *testing.T) {
|
||||
driveSetTests(t, NewThreadsafeSet())
|
||||
}
|
||||
|
||||
// Check that two slices contents are equal; order is irrelevant
|
||||
func equal(a, b []string) bool {
|
||||
as := sort.StringSlice(a)
|
||||
bs := sort.StringSlice(b)
|
||||
as.Sort()
|
||||
bs.Sort()
|
||||
return reflect.DeepEqual(as, bs)
|
||||
}
|
||||
|
||||
func driveSetTests(t *testing.T, s Set) {
|
||||
// Verify operations on an empty set
|
||||
eValues := []string{}
|
||||
values := s.Values()
|
||||
if !reflect.DeepEqual(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
if l := s.Length(); l != 0 {
|
||||
t.Fatalf("Expected length=0, got %d", l)
|
||||
}
|
||||
for _, v := range []string{"foo", "bar", "baz"} {
|
||||
if s.Contains(v) {
|
||||
t.Fatalf("Expect s.Contains(%q) to be fale, got true", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Add three items, ensure they show up
|
||||
s.Add("foo")
|
||||
s.Add("bar")
|
||||
s.Add("baz")
|
||||
|
||||
eValues = []string{"foo", "bar", "baz"}
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
|
||||
for _, v := range eValues {
|
||||
if !s.Contains(v) {
|
||||
t.Fatalf("Expect s.Contains(%q) to be true, got false", v)
|
||||
}
|
||||
}
|
||||
|
||||
if l := s.Length(); l != 3 {
|
||||
t.Fatalf("Expected length=3, got %d", l)
|
||||
}
|
||||
|
||||
// Add the same item a second time, ensuring it is not duplicated
|
||||
s.Add("foo")
|
||||
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
if l := s.Length(); l != 3 {
|
||||
t.Fatalf("Expected length=3, got %d", l)
|
||||
}
|
||||
|
||||
// Remove all items, ensure they are gone
|
||||
s.Remove("foo")
|
||||
s.Remove("bar")
|
||||
s.Remove("baz")
|
||||
|
||||
eValues = []string{}
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
|
||||
if l := s.Length(); l != 0 {
|
||||
t.Fatalf("Expected length=0, got %d", l)
|
||||
}
|
||||
|
||||
// Create new copies of the set, and ensure they are unlinked to the
|
||||
// original Set by making modifications
|
||||
s.Add("foo")
|
||||
s.Add("bar")
|
||||
cp1 := s.Copy()
|
||||
cp2 := s.Copy()
|
||||
s.Remove("foo")
|
||||
cp3 := s.Copy()
|
||||
cp1.Add("baz")
|
||||
|
||||
for i, tt := range []struct {
|
||||
want []string
|
||||
got []string
|
||||
}{
|
||||
{[]string{"bar"}, s.Values()},
|
||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
||||
{[]string{"foo", "bar"}, cp2.Values()},
|
||||
{[]string{"bar"}, cp3.Values()},
|
||||
} {
|
||||
if !equal(tt.want, tt.got) {
|
||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
||||
}
|
||||
}
|
||||
|
||||
for i, tt := range []struct {
|
||||
want bool
|
||||
got bool
|
||||
}{
|
||||
{true, s.Equals(cp3)},
|
||||
{true, cp3.Equals(s)},
|
||||
{false, s.Equals(cp2)},
|
||||
{false, s.Equals(cp1)},
|
||||
{false, cp1.Equals(s)},
|
||||
{false, cp2.Equals(s)},
|
||||
{false, cp2.Equals(cp1)},
|
||||
} {
|
||||
if tt.got != tt.want {
|
||||
t.Fatalf("case %d: want %t, got %t", i, tt.want, tt.got)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract values from a Set, ensuring a new Set is created and
|
||||
// the original Sets are unmodified
|
||||
sub1 := cp1.Sub(s)
|
||||
sub2 := cp2.Sub(cp1)
|
||||
|
||||
for i, tt := range []struct {
|
||||
want []string
|
||||
got []string
|
||||
}{
|
||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
||||
{[]string{"foo", "bar"}, cp2.Values()},
|
||||
{[]string{"bar"}, s.Values()},
|
||||
{[]string{"foo", "baz"}, sub1.Values()},
|
||||
{[]string{}, sub2.Values()},
|
||||
} {
|
||||
if !equal(tt.want, tt.got) {
|
||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsafeSetContainsAll(t *testing.T) {
|
||||
vals := []string{"foo", "bar", "baz"}
|
||||
s := NewUnsafeSet(vals...)
|
||||
|
||||
tests := []struct {
|
||||
strs []string
|
||||
wcontain bool
|
||||
}{
|
||||
{[]string{}, true},
|
||||
{vals[:1], true},
|
||||
{vals[:2], true},
|
||||
{vals, true},
|
||||
{[]string{"cuz"}, false},
|
||||
{[]string{vals[0], "cuz"}, false},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if g := s.ContainsAll(tt.strs); g != tt.wcontain {
|
||||
t.Errorf("#%d: ok = %v, want %v", i, g, tt.wcontain)
|
||||
}
|
||||
}
|
||||
}
|
30
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice_test.go
generated
vendored
30
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice_test.go
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUint64Slice(t *testing.T) {
|
||||
g := Uint64Slice{10, 500, 5, 1, 100, 25}
|
||||
w := Uint64Slice{1, 5, 10, 25, 100, 500}
|
||||
sort.Sort(g)
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
169
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls_test.go
generated
vendored
169
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls_test.go
generated
vendored
|
@ -1,169 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestNewURLs(t *testing.T) {
|
||||
tests := []struct {
|
||||
strs []string
|
||||
wurls URLs
|
||||
}{
|
||||
{
|
||||
[]string{"http://127.0.0.1:2379"},
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
|
||||
},
|
||||
// it can trim space
|
||||
{
|
||||
[]string{" http://127.0.0.1:2379 "},
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
|
||||
},
|
||||
// it does sort
|
||||
{
|
||||
[]string{
|
||||
"http://127.0.0.2:2379",
|
||||
"http://127.0.0.1:2379",
|
||||
},
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.2:2379",
|
||||
}),
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
urls, _ := NewURLs(tt.strs)
|
||||
if !reflect.DeepEqual(urls, tt.wurls) {
|
||||
t.Errorf("#%d: urls = %+v, want %+v", i, urls, tt.wurls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsString(t *testing.T) {
|
||||
tests := []struct {
|
||||
us URLs
|
||||
wstr string
|
||||
}{
|
||||
{
|
||||
URLs{},
|
||||
"",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
|
||||
"http://127.0.0.1:2379",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.2:2379",
|
||||
}),
|
||||
"http://127.0.0.1:2379,http://127.0.0.2:2379",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.2:2379",
|
||||
"http://127.0.0.1:2379",
|
||||
}),
|
||||
"http://127.0.0.2:2379,http://127.0.0.1:2379",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
g := tt.us.String()
|
||||
if g != tt.wstr {
|
||||
t.Errorf("#%d: string = %s, want %s", i, g, tt.wstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsSort(t *testing.T) {
|
||||
g := testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.4:2379",
|
||||
"http://127.0.0.2:2379",
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.3:2379",
|
||||
})
|
||||
w := testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.2:2379",
|
||||
"http://127.0.0.3:2379",
|
||||
"http://127.0.0.4:2379",
|
||||
})
|
||||
gurls := URLs(g)
|
||||
gurls.Sort()
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("URLs after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsStringSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
us URLs
|
||||
wstr []string
|
||||
}{
|
||||
{
|
||||
URLs{},
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
|
||||
[]string{"http://127.0.0.1:2379"},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.2:2379",
|
||||
}),
|
||||
[]string{"http://127.0.0.1:2379", "http://127.0.0.2:2379"},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.2:2379",
|
||||
"http://127.0.0.1:2379",
|
||||
}),
|
||||
[]string{"http://127.0.0.2:2379", "http://127.0.0.1:2379"},
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
g := tt.us.StringSlice()
|
||||
if !reflect.DeepEqual(g, tt.wstr) {
|
||||
t.Errorf("#%d: string slice = %+v, want %+v", i, g, tt.wstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewURLsFail(t *testing.T) {
|
||||
tests := [][]string{
|
||||
// no urls given
|
||||
{},
|
||||
// missing protocol scheme
|
||||
{"://127.0.0.1:2379"},
|
||||
// unsupported scheme
|
||||
{"mailto://127.0.0.1:2379"},
|
||||
// not conform to host:port
|
||||
{"http://127.0.0.1"},
|
||||
// contain a path
|
||||
{"http://127.0.0.1:2379/path"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
_, err := NewURLs(tt)
|
||||
if err == nil {
|
||||
t.Errorf("#%d: err = nil, but error", i)
|
||||
}
|
||||
}
|
||||
}
|
69
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urlsmap_test.go
generated
vendored
69
libnetwork/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urlsmap_test.go
generated
vendored
|
@ -1,69 +0,0 @@
|
|||
// Copyright 2015 CoreOS, 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
|
||||
//
|
||||
// http://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.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestParseInitialCluster(t *testing.T) {
|
||||
c, err := NewURLsMap("mem1=http://10.0.0.1:2379,mem1=http://128.193.4.20:2379,mem2=http://10.0.0.2:2379,default=http://127.0.0.1:2379")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %v", err)
|
||||
}
|
||||
wc := URLsMap(map[string]URLs{
|
||||
"mem1": testutil.MustNewURLs(t, []string{"http://10.0.0.1:2379", "http://128.193.4.20:2379"}),
|
||||
"mem2": testutil.MustNewURLs(t, []string{"http://10.0.0.2:2379"}),
|
||||
"default": testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
|
||||
})
|
||||
if !reflect.DeepEqual(c, wc) {
|
||||
t.Errorf("cluster = %+v, want %+v", c, wc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInitialClusterBad(t *testing.T) {
|
||||
tests := []string{
|
||||
// invalid URL
|
||||
"%^",
|
||||
// no URL defined for member
|
||||
"mem1=,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
|
||||
"mem1,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
|
||||
// bad URL for member
|
||||
"default=http://localhost/",
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if _, err := NewURLsMap(tt); err == nil {
|
||||
t.Errorf("#%d: unexpected successful parse, want err", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameURLPairsString(t *testing.T) {
|
||||
cls := URLsMap(map[string]URLs{
|
||||
"abc": testutil.MustNewURLs(t, []string{"http://1.1.1.1:1111", "http://0.0.0.0:0000"}),
|
||||
"def": testutil.MustNewURLs(t, []string{"http://2.2.2.2:2222"}),
|
||||
"ghi": testutil.MustNewURLs(t, []string{"http://3.3.3.3:1234", "http://127.0.0.1:2380"}),
|
||||
// no PeerURLs = not included
|
||||
"four": testutil.MustNewURLs(t, []string{}),
|
||||
"five": testutil.MustNewURLs(t, nil),
|
||||
})
|
||||
w := "abc=http://0.0.0.0:0000,abc=http://1.1.1.1:1111,def=http://2.2.2.2:2222,ghi=http://127.0.0.1:2380,ghi=http://3.3.3.3:1234"
|
||||
if g := cls.String(); g != w {
|
||||
t.Fatalf("NameURLPairs.String():\ngot %#v\nwant %#v", g, w)
|
||||
}
|
||||
}
|
523
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/bench_test.go
generated
vendored
523
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/bench_test.go
generated
vendored
|
@ -1,523 +0,0 @@
|
|||
package mapset
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func nrand(n int) []int {
|
||||
i := make([]int, n)
|
||||
for ind := range i {
|
||||
i[ind] = rand.Int()
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func toInterfaces(i []int) []interface{} {
|
||||
ifs := make([]interface{}, len(i))
|
||||
for ind, v := range i {
|
||||
ifs[ind] = v
|
||||
}
|
||||
return ifs
|
||||
}
|
||||
|
||||
func benchAdd(b *testing.B, s Set) {
|
||||
nums := nrand(b.N)
|
||||
b.ResetTimer()
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddSafe(b *testing.B) {
|
||||
benchAdd(b, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkAddUnsafe(b *testing.B) {
|
||||
benchAdd(b, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchRemove(b *testing.B, s Set) {
|
||||
nums := nrand(b.N)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for _, v := range nums {
|
||||
s.Remove(v)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRemoveSafe(b *testing.B) {
|
||||
benchRemove(b, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkRemoveUnsafe(b *testing.B) {
|
||||
benchRemove(b, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchCardinality(b *testing.B, s Set) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Cardinality()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCardinalitySafe(b *testing.B) {
|
||||
benchCardinality(b, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkCardinalityUnsafe(b *testing.B) {
|
||||
benchCardinality(b, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchClear(b *testing.B, s Set) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkClearSafe(b *testing.B) {
|
||||
benchClear(b, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkClearUnsafe(b *testing.B) {
|
||||
benchClear(b, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchClone(b *testing.B, n int, s Set) {
|
||||
nums := toInterfaces(nrand(n))
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Clone()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkClone1Safe(b *testing.B) {
|
||||
benchClone(b, 1, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkClone1Unsafe(b *testing.B) {
|
||||
benchClone(b, 1, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkClone10Safe(b *testing.B) {
|
||||
benchClone(b, 10, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkClone10Unsafe(b *testing.B) {
|
||||
benchClone(b, 10, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkClone100Safe(b *testing.B) {
|
||||
benchClone(b, 100, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkClone100Unsafe(b *testing.B) {
|
||||
benchClone(b, 100, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchContains(b *testing.B, n int, s Set) {
|
||||
nums := toInterfaces(nrand(n))
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
nums[n-1] = -1 // Definitely not in s
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Contains(nums...)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkContains1Safe(b *testing.B) {
|
||||
benchContains(b, 1, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkContains1Unsafe(b *testing.B) {
|
||||
benchContains(b, 1, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkContains10Safe(b *testing.B) {
|
||||
benchContains(b, 10, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkContains10Unsafe(b *testing.B) {
|
||||
benchContains(b, 10, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkContains100Safe(b *testing.B) {
|
||||
benchContains(b, 100, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkContains100Unsafe(b *testing.B) {
|
||||
benchContains(b, 100, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchEqual(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Equal(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEqual1Safe(b *testing.B) {
|
||||
benchEqual(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkEqual1Unsafe(b *testing.B) {
|
||||
benchEqual(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkEqual10Safe(b *testing.B) {
|
||||
benchEqual(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkEqual10Unsafe(b *testing.B) {
|
||||
benchEqual(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkEqual100Safe(b *testing.B) {
|
||||
benchEqual(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkEqual100Unsafe(b *testing.B) {
|
||||
benchEqual(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchDifference(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
for _, v := range nums[:n/2] {
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Difference(t)
|
||||
}
|
||||
}
|
||||
|
||||
func benchIsSubset(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.IsSubset(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset1Safe(b *testing.B) {
|
||||
benchIsSubset(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset1Unsafe(b *testing.B) {
|
||||
benchIsSubset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset10Safe(b *testing.B) {
|
||||
benchIsSubset(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset10Unsafe(b *testing.B) {
|
||||
benchIsSubset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset100Safe(b *testing.B) {
|
||||
benchIsSubset(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSubset100Unsafe(b *testing.B) {
|
||||
benchIsSubset(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchIsSuperset(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.IsSuperset(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset1Safe(b *testing.B) {
|
||||
benchIsSuperset(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset1Unsafe(b *testing.B) {
|
||||
benchIsSuperset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset10Safe(b *testing.B) {
|
||||
benchIsSuperset(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset10Unsafe(b *testing.B) {
|
||||
benchIsSuperset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset100Safe(b *testing.B) {
|
||||
benchIsSuperset(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIsSuperset100Unsafe(b *testing.B) {
|
||||
benchIsSuperset(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference1Safe(b *testing.B) {
|
||||
benchDifference(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference1Unsafe(b *testing.B) {
|
||||
benchDifference(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference10Safe(b *testing.B) {
|
||||
benchDifference(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference10Unsafe(b *testing.B) {
|
||||
benchDifference(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference100Safe(b *testing.B) {
|
||||
benchDifference(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkDifference100Unsafe(b *testing.B) {
|
||||
benchDifference(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchIntersect(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(int(float64(n) * float64(1.5)))
|
||||
for _, v := range nums[:n] {
|
||||
s.Add(v)
|
||||
}
|
||||
for _, v := range nums[n/2:] {
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Intersect(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIntersect1Safe(b *testing.B) {
|
||||
benchIntersect(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIntersect1Unsafe(b *testing.B) {
|
||||
benchIntersect(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIntersect10Safe(b *testing.B) {
|
||||
benchIntersect(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIntersect10Unsafe(b *testing.B) {
|
||||
benchIntersect(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIntersect100Safe(b *testing.B) {
|
||||
benchIntersect(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIntersect100Unsafe(b *testing.B) {
|
||||
benchIntersect(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchSymmetricDifference(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(int(float64(n) * float64(1.5)))
|
||||
for _, v := range nums[:n] {
|
||||
s.Add(v)
|
||||
}
|
||||
for _, v := range nums[n/2:] {
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.SymmetricDifference(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference1Safe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference1Unsafe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference10Safe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference10Unsafe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference100Safe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkSymmetricDifference100Unsafe(b *testing.B) {
|
||||
benchSymmetricDifference(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchUnion(b *testing.B, n int, s, t Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums[:n/2] {
|
||||
s.Add(v)
|
||||
}
|
||||
for _, v := range nums[n/2:] {
|
||||
t.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Union(t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnion1Safe(b *testing.B) {
|
||||
benchUnion(b, 1, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkUnion1Unsafe(b *testing.B) {
|
||||
benchUnion(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkUnion10Safe(b *testing.B) {
|
||||
benchUnion(b, 10, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkUnion10Unsafe(b *testing.B) {
|
||||
benchUnion(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkUnion100Safe(b *testing.B) {
|
||||
benchUnion(b, 100, NewSet(), NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkUnion100Unsafe(b *testing.B) {
|
||||
benchUnion(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchIter(b *testing.B, n int, s Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := s.Iter()
|
||||
for _ = range c {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIter1Safe(b *testing.B) {
|
||||
benchIter(b, 1, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIter1Unsafe(b *testing.B) {
|
||||
benchIter(b, 1, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIter10Safe(b *testing.B) {
|
||||
benchIter(b, 10, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIter10Unsafe(b *testing.B) {
|
||||
benchIter(b, 10, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkIter100Safe(b *testing.B) {
|
||||
benchIter(b, 100, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkIter100Unsafe(b *testing.B) {
|
||||
benchIter(b, 100, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchString(b *testing.B, n int, s Set) {
|
||||
nums := nrand(n)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.String()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkString1Safe(b *testing.B) {
|
||||
benchString(b, 1, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkString1Unsafe(b *testing.B) {
|
||||
benchString(b, 1, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkString10Safe(b *testing.B) {
|
||||
benchString(b, 10, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkString10Unsafe(b *testing.B) {
|
||||
benchString(b, 10, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func BenchmarkString100Safe(b *testing.B) {
|
||||
benchString(b, 100, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkString100Unsafe(b *testing.B) {
|
||||
benchString(b, 100, NewThreadUnsafeSet())
|
||||
}
|
||||
|
||||
func benchToSlice(b *testing.B, s Set) {
|
||||
nums := nrand(b.N)
|
||||
for _, v := range nums {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.ToSlice()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToSliceSafe(b *testing.B) {
|
||||
benchToSlice(b, NewSet())
|
||||
}
|
||||
|
||||
func BenchmarkToSliceUnsafe(b *testing.B) {
|
||||
benchToSlice(b, NewThreadUnsafeSet())
|
||||
}
|
910
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/set_test.go
generated
vendored
910
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/set_test.go
generated
vendored
|
@ -1,910 +0,0 @@
|
|||
/*
|
||||
Open Source Initiative OSI - The MIT License (MIT):Licensing
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package mapset
|
||||
|
||||
import "testing"
|
||||
|
||||
func makeSet(ints []int) Set {
|
||||
set := NewSet()
|
||||
for _, i := range ints {
|
||||
set.Add(i)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func makeUnsafeSet(ints []int) Set {
|
||||
set := NewThreadUnsafeSet()
|
||||
for _, i := range ints {
|
||||
set.Add(i)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func Test_NewSet(t *testing.T) {
|
||||
a := NewSet()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("NewSet should start out as an empty set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewUnsafeSet(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("NewSet should start out as an empty set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AddSet(t *testing.T) {
|
||||
a := makeSet([]int{1, 2, 3})
|
||||
|
||||
if a.Cardinality() != 3 {
|
||||
t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AddUnsafeSet(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{1, 2, 3})
|
||||
|
||||
if a.Cardinality() != 3 {
|
||||
t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AddSetNoDuplicate(t *testing.T) {
|
||||
a := makeSet([]int{7, 5, 3, 7})
|
||||
|
||||
if a.Cardinality() != 3 {
|
||||
t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate")
|
||||
}
|
||||
|
||||
if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) {
|
||||
t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AddUnsafeSetNoDuplicate(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{7, 5, 3, 7})
|
||||
|
||||
if a.Cardinality() != 3 {
|
||||
t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate")
|
||||
}
|
||||
|
||||
if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) {
|
||||
t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RemoveSet(t *testing.T) {
|
||||
a := makeSet([]int{6, 3, 1})
|
||||
|
||||
a.Remove(3)
|
||||
|
||||
if a.Cardinality() != 2 {
|
||||
t.Error("RemoveSet should only have 2 items in the set")
|
||||
}
|
||||
|
||||
if !(a.Contains(6) && a.Contains(1)) {
|
||||
t.Error("RemoveSet should have only items 6 and 1 in the set")
|
||||
}
|
||||
|
||||
a.Remove(6)
|
||||
a.Remove(1)
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("RemoveSet should be an empty set after removing 6 and 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RemoveUnsafeSet(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{6, 3, 1})
|
||||
|
||||
a.Remove(3)
|
||||
|
||||
if a.Cardinality() != 2 {
|
||||
t.Error("RemoveSet should only have 2 items in the set")
|
||||
}
|
||||
|
||||
if !(a.Contains(6) && a.Contains(1)) {
|
||||
t.Error("RemoveSet should have only items 6 and 1 in the set")
|
||||
}
|
||||
|
||||
a.Remove(6)
|
||||
a.Remove(1)
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("RemoveSet should be an empty set after removing 6 and 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ContainsSet(t *testing.T) {
|
||||
a := NewSet()
|
||||
|
||||
a.Add(71)
|
||||
|
||||
if !a.Contains(71) {
|
||||
t.Error("ContainsSet should contain 71")
|
||||
}
|
||||
|
||||
a.Remove(71)
|
||||
|
||||
if a.Contains(71) {
|
||||
t.Error("ContainsSet should not contain 71")
|
||||
}
|
||||
|
||||
a.Add(13)
|
||||
a.Add(7)
|
||||
a.Add(1)
|
||||
|
||||
if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) {
|
||||
t.Error("ContainsSet should contain 13, 7, 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ContainsUnsafeSet(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
a.Add(71)
|
||||
|
||||
if !a.Contains(71) {
|
||||
t.Error("ContainsSet should contain 71")
|
||||
}
|
||||
|
||||
a.Remove(71)
|
||||
|
||||
if a.Contains(71) {
|
||||
t.Error("ContainsSet should not contain 71")
|
||||
}
|
||||
|
||||
a.Add(13)
|
||||
a.Add(7)
|
||||
a.Add(1)
|
||||
|
||||
if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) {
|
||||
t.Error("ContainsSet should contain 13, 7, 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ContainsMultipleSet(t *testing.T) {
|
||||
a := makeSet([]int{8, 6, 7, 5, 3, 0, 9})
|
||||
|
||||
if !a.Contains(8, 6, 7, 5, 3, 0, 9) {
|
||||
t.Error("ContainsAll should contain Jenny's phone number")
|
||||
}
|
||||
|
||||
if a.Contains(8, 6, 11, 5, 3, 0, 9) {
|
||||
t.Error("ContainsAll should not have all of these numbers")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ContainsMultipleUnsafeSet(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{8, 6, 7, 5, 3, 0, 9})
|
||||
|
||||
if !a.Contains(8, 6, 7, 5, 3, 0, 9) {
|
||||
t.Error("ContainsAll should contain Jenny's phone number")
|
||||
}
|
||||
|
||||
if a.Contains(8, 6, 11, 5, 3, 0, 9) {
|
||||
t.Error("ContainsAll should not have all of these numbers")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClearSet(t *testing.T) {
|
||||
a := makeSet([]int{2, 5, 9, 10})
|
||||
|
||||
a.Clear()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("ClearSet should be an empty set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClearUnsafeSet(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{2, 5, 9, 10})
|
||||
|
||||
a.Clear()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("ClearSet should be an empty set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CardinalitySet(t *testing.T) {
|
||||
a := NewSet()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should be an empty set")
|
||||
}
|
||||
|
||||
a.Add(1)
|
||||
|
||||
if a.Cardinality() != 1 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
|
||||
a.Remove(1)
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should be an empty set")
|
||||
}
|
||||
|
||||
a.Add(9)
|
||||
|
||||
if a.Cardinality() != 1 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
|
||||
a.Clear()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CardinalityUnsafeSet(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should be an empty set")
|
||||
}
|
||||
|
||||
a.Add(1)
|
||||
|
||||
if a.Cardinality() != 1 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
|
||||
a.Remove(1)
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should be an empty set")
|
||||
}
|
||||
|
||||
a.Add(9)
|
||||
|
||||
if a.Cardinality() != 1 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
|
||||
a.Clear()
|
||||
|
||||
if a.Cardinality() != 0 {
|
||||
t.Error("set should have a size of 1")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetIsSubset(t *testing.T) {
|
||||
a := makeSet([]int{1, 2, 3, 5, 7})
|
||||
|
||||
b := NewSet()
|
||||
b.Add(3)
|
||||
b.Add(5)
|
||||
b.Add(7)
|
||||
|
||||
if !b.IsSubset(a) {
|
||||
t.Error("set b should be a subset of set a")
|
||||
}
|
||||
|
||||
b.Add(72)
|
||||
|
||||
if b.IsSubset(a) {
|
||||
t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetIsSubset(t *testing.T) {
|
||||
a := makeUnsafeSet([]int{1, 2, 3, 5, 7})
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
b.Add(3)
|
||||
b.Add(5)
|
||||
b.Add(7)
|
||||
|
||||
if !b.IsSubset(a) {
|
||||
t.Error("set b should be a subset of set a")
|
||||
}
|
||||
|
||||
b.Add(72)
|
||||
|
||||
if b.IsSubset(a) {
|
||||
t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetIsSuperSet(t *testing.T) {
|
||||
a := NewSet()
|
||||
a.Add(9)
|
||||
a.Add(5)
|
||||
a.Add(2)
|
||||
a.Add(1)
|
||||
a.Add(11)
|
||||
|
||||
b := NewSet()
|
||||
b.Add(5)
|
||||
b.Add(2)
|
||||
b.Add(11)
|
||||
|
||||
if !a.IsSuperset(b) {
|
||||
t.Error("set a should be a superset of set b")
|
||||
}
|
||||
|
||||
b.Add(42)
|
||||
|
||||
if a.IsSuperset(b) {
|
||||
t.Error("set a should not be a superset of set b because set a has a 42")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetIsSuperSet(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
a.Add(9)
|
||||
a.Add(5)
|
||||
a.Add(2)
|
||||
a.Add(1)
|
||||
a.Add(11)
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
b.Add(5)
|
||||
b.Add(2)
|
||||
b.Add(11)
|
||||
|
||||
if !a.IsSuperset(b) {
|
||||
t.Error("set a should be a superset of set b")
|
||||
}
|
||||
|
||||
b.Add(42)
|
||||
|
||||
if a.IsSuperset(b) {
|
||||
t.Error("set a should not be a superset of set b because set a has a 42")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetUnion(t *testing.T) {
|
||||
a := NewSet()
|
||||
|
||||
b := NewSet()
|
||||
b.Add(1)
|
||||
b.Add(2)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
|
||||
c := a.Union(b)
|
||||
|
||||
if c.Cardinality() != 5 {
|
||||
t.Error("set c is unioned with an empty set and therefore should have 5 elements in it")
|
||||
}
|
||||
|
||||
d := NewSet()
|
||||
d.Add(10)
|
||||
d.Add(14)
|
||||
d.Add(0)
|
||||
|
||||
e := c.Union(d)
|
||||
if e.Cardinality() != 8 {
|
||||
t.Error("set e should should have 8 elements in it after being unioned with set c to d")
|
||||
}
|
||||
|
||||
f := NewSet()
|
||||
f.Add(14)
|
||||
f.Add(3)
|
||||
|
||||
g := f.Union(e)
|
||||
if g.Cardinality() != 8 {
|
||||
t.Error("set g should still ahve 8 elements in it after being unioned with set f that has duplicates")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetUnion(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
b.Add(1)
|
||||
b.Add(2)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
|
||||
c := a.Union(b)
|
||||
|
||||
if c.Cardinality() != 5 {
|
||||
t.Error("set c is unioned with an empty set and therefore should have 5 elements in it")
|
||||
}
|
||||
|
||||
d := NewThreadUnsafeSet()
|
||||
d.Add(10)
|
||||
d.Add(14)
|
||||
d.Add(0)
|
||||
|
||||
e := c.Union(d)
|
||||
if e.Cardinality() != 8 {
|
||||
t.Error("set e should should have 8 elements in it after being unioned with set c to d")
|
||||
}
|
||||
|
||||
f := NewThreadUnsafeSet()
|
||||
f.Add(14)
|
||||
f.Add(3)
|
||||
|
||||
g := f.Union(e)
|
||||
if g.Cardinality() != 8 {
|
||||
t.Error("set g should still ahve 8 elements in it after being unioned with set f that has duplicates")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetIntersect(t *testing.T) {
|
||||
a := NewSet()
|
||||
a.Add(1)
|
||||
a.Add(3)
|
||||
a.Add(5)
|
||||
|
||||
b := NewSet()
|
||||
a.Add(2)
|
||||
a.Add(4)
|
||||
a.Add(6)
|
||||
|
||||
c := a.Intersect(b)
|
||||
|
||||
if c.Cardinality() != 0 {
|
||||
t.Error("set c should be the empty set because there is no common items to intersect")
|
||||
}
|
||||
|
||||
a.Add(10)
|
||||
b.Add(10)
|
||||
|
||||
d := a.Intersect(b)
|
||||
|
||||
if !(d.Cardinality() == 1 && d.Contains(10)) {
|
||||
t.Error("set d should have a size of 1 and contain the item 10")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetIntersect(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
a.Add(1)
|
||||
a.Add(3)
|
||||
a.Add(5)
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
a.Add(2)
|
||||
a.Add(4)
|
||||
a.Add(6)
|
||||
|
||||
c := a.Intersect(b)
|
||||
|
||||
if c.Cardinality() != 0 {
|
||||
t.Error("set c should be the empty set because there is no common items to intersect")
|
||||
}
|
||||
|
||||
a.Add(10)
|
||||
b.Add(10)
|
||||
|
||||
d := a.Intersect(b)
|
||||
|
||||
if !(d.Cardinality() == 1 && d.Contains(10)) {
|
||||
t.Error("set d should have a size of 1 and contain the item 10")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetDifference(t *testing.T) {
|
||||
a := NewSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
a.Add(3)
|
||||
|
||||
b := NewSet()
|
||||
b.Add(1)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
b.Add(6)
|
||||
b.Add(99)
|
||||
|
||||
c := a.Difference(b)
|
||||
|
||||
if !(c.Cardinality() == 1 && c.Contains(2)) {
|
||||
t.Error("the difference of set a to b is the set of 1 item: 2")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetDifference(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
a.Add(3)
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
b.Add(1)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
b.Add(6)
|
||||
b.Add(99)
|
||||
|
||||
c := a.Difference(b)
|
||||
|
||||
if !(c.Cardinality() == 1 && c.Contains(2)) {
|
||||
t.Error("the difference of set a to b is the set of 1 item: 2")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetSymmetricDifference(t *testing.T) {
|
||||
a := NewSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
a.Add(3)
|
||||
a.Add(45)
|
||||
|
||||
b := NewSet()
|
||||
b.Add(1)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
b.Add(6)
|
||||
b.Add(99)
|
||||
|
||||
c := a.SymmetricDifference(b)
|
||||
|
||||
if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) {
|
||||
t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetSymmetricDifference(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
a.Add(3)
|
||||
a.Add(45)
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
b.Add(1)
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
b.Add(5)
|
||||
b.Add(6)
|
||||
b.Add(99)
|
||||
|
||||
c := a.SymmetricDifference(b)
|
||||
|
||||
if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) {
|
||||
t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetEqual(t *testing.T) {
|
||||
a := NewSet()
|
||||
b := NewSet()
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("Both a and b are empty sets, and should be equal")
|
||||
}
|
||||
|
||||
a.Add(10)
|
||||
|
||||
if a.Equal(b) {
|
||||
t.Error("a should not be equal to b because b is empty and a has item 1 in it")
|
||||
}
|
||||
|
||||
b.Add(10)
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("a is now equal again to b because both have the item 10 in them")
|
||||
}
|
||||
|
||||
b.Add(8)
|
||||
b.Add(3)
|
||||
b.Add(47)
|
||||
|
||||
if a.Equal(b) {
|
||||
t.Error("b has 3 more elements in it so therefore should not be equal to a")
|
||||
}
|
||||
|
||||
a.Add(8)
|
||||
a.Add(3)
|
||||
a.Add(47)
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("a and b should be equal with the same number of elements")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetEqual(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
b := NewThreadUnsafeSet()
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("Both a and b are empty sets, and should be equal")
|
||||
}
|
||||
|
||||
a.Add(10)
|
||||
|
||||
if a.Equal(b) {
|
||||
t.Error("a should not be equal to b because b is empty and a has item 1 in it")
|
||||
}
|
||||
|
||||
b.Add(10)
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("a is now equal again to b because both have the item 10 in them")
|
||||
}
|
||||
|
||||
b.Add(8)
|
||||
b.Add(3)
|
||||
b.Add(47)
|
||||
|
||||
if a.Equal(b) {
|
||||
t.Error("b has 3 more elements in it so therefore should not be equal to a")
|
||||
}
|
||||
|
||||
a.Add(8)
|
||||
a.Add(3)
|
||||
a.Add(47)
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("a and b should be equal with the same number of elements")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetClone(t *testing.T) {
|
||||
a := NewSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
|
||||
b := a.Clone()
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("Clones should be equal")
|
||||
}
|
||||
|
||||
a.Add(3)
|
||||
if a.Equal(b) {
|
||||
t.Error("a contains one more element, they should not be equal")
|
||||
}
|
||||
|
||||
c := a.Clone()
|
||||
c.Remove(1)
|
||||
|
||||
if a.Equal(c) {
|
||||
t.Error("C contains one element less, they should not be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeSetClone(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
|
||||
b := a.Clone()
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("Clones should be equal")
|
||||
}
|
||||
|
||||
a.Add(3)
|
||||
if a.Equal(b) {
|
||||
t.Error("a contains one more element, they should not be equal")
|
||||
}
|
||||
|
||||
c := a.Clone()
|
||||
c.Remove(1)
|
||||
|
||||
if a.Equal(c) {
|
||||
t.Error("C contains one element less, they should not be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Iterator(t *testing.T) {
|
||||
a := NewSet()
|
||||
|
||||
a.Add("Z")
|
||||
a.Add("Y")
|
||||
a.Add("X")
|
||||
a.Add("W")
|
||||
|
||||
b := NewSet()
|
||||
for val := range a.Iter() {
|
||||
b.Add(val)
|
||||
}
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("The sets are not equal after iterating through the first set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UnsafeIterator(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
a.Add("Z")
|
||||
a.Add("Y")
|
||||
a.Add("X")
|
||||
a.Add("W")
|
||||
|
||||
b := NewThreadUnsafeSet()
|
||||
for val := range a.Iter() {
|
||||
b.Add(val)
|
||||
}
|
||||
|
||||
if !a.Equal(b) {
|
||||
t.Error("The sets are not equal after iterating through the first set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PowerSet(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
|
||||
a.Add(1)
|
||||
a.Add("delta")
|
||||
a.Add("chi")
|
||||
a.Add(4)
|
||||
|
||||
b := a.PowerSet()
|
||||
if b.Cardinality() != 16 {
|
||||
t.Error("unexpected PowerSet cardinality")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_EmptySetProperties(t *testing.T) {
|
||||
empty := NewSet()
|
||||
|
||||
a := NewSet()
|
||||
a.Add(1)
|
||||
a.Add("foo")
|
||||
a.Add("bar")
|
||||
|
||||
b := NewSet()
|
||||
b.Add("one")
|
||||
b.Add("two")
|
||||
b.Add(3)
|
||||
b.Add(4)
|
||||
|
||||
c := NewSet()
|
||||
|
||||
if !empty.IsSubset(a) || !empty.IsSubset(b) {
|
||||
t.Error("The empty set is supposed to be a subset of all sets")
|
||||
}
|
||||
|
||||
if !a.IsSuperset(empty) || !b.IsSuperset(empty) {
|
||||
t.Error("All sets are supposed to be a superset of the empty set")
|
||||
}
|
||||
|
||||
if !empty.IsSubset(empty) || !empty.IsSuperset(empty) {
|
||||
t.Error("The empty set is supposed to be a subset and a superset of itself")
|
||||
}
|
||||
|
||||
c = a.Union(empty)
|
||||
if !c.Equal(a) {
|
||||
t.Error("The union of any set with the empty set is supposed to be equal to itself")
|
||||
}
|
||||
|
||||
c = a.Intersect(empty)
|
||||
if !c.Equal(empty) {
|
||||
t.Error("The intesection of any set with the empty set is supposed to be the empty set")
|
||||
}
|
||||
|
||||
c = a.CartesianProduct(empty)
|
||||
if c.Cardinality() != 0 {
|
||||
t.Error("Cartesian product of any set and the empty set must be the empty set")
|
||||
}
|
||||
|
||||
if empty.Cardinality() != 0 {
|
||||
t.Error("Cardinality of the empty set is supposed to be zero")
|
||||
}
|
||||
|
||||
c = empty.PowerSet()
|
||||
if c.Cardinality() != 1 {
|
||||
t.Error("Cardinality of the power set of the empty set is supposed to be one { {} }")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CartesianProduct(t *testing.T) {
|
||||
a := NewThreadUnsafeSet()
|
||||
b := NewThreadUnsafeSet()
|
||||
empty := NewThreadUnsafeSet()
|
||||
|
||||
a.Add(1)
|
||||
a.Add(2)
|
||||
a.Add(3)
|
||||
|
||||
b.Add("one")
|
||||
b.Add("two")
|
||||
b.Add("three")
|
||||
b.Add("alpha")
|
||||
b.Add("gamma")
|
||||
|
||||
c := a.CartesianProduct(b)
|
||||
d := b.CartesianProduct(a)
|
||||
|
||||
if c.Cardinality() != d.Cardinality() {
|
||||
t.Error("Cardinality of AxB must be equal to BxA")
|
||||
}
|
||||
|
||||
if c.Cardinality() != (a.Cardinality() * b.Cardinality()) {
|
||||
t.Error("Unexpected cardinality for cartesian product set")
|
||||
}
|
||||
|
||||
c = a.CartesianProduct(empty)
|
||||
d = empty.CartesianProduct(b)
|
||||
|
||||
if c.Cardinality() != 0 || d.Cardinality() != 0 {
|
||||
t.Error("Cartesian product of any set and the emtpy set Ax0 || 0xA must be the empty set")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ToSliceUnthreadsafe(t *testing.T) {
|
||||
s := makeUnsafeSet([]int{1, 2, 3})
|
||||
setAsSlice := s.ToSlice()
|
||||
if len(setAsSlice) != s.Cardinality() {
|
||||
t.Errorf("Set length is incorrect: %v", len(setAsSlice))
|
||||
}
|
||||
|
||||
for _, i := range setAsSlice {
|
||||
if !s.Contains(i) {
|
||||
t.Errorf("Set is missing element: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Example(t *testing.T) {
|
||||
/*
|
||||
requiredClasses := NewSet()
|
||||
requiredClasses.Add("Cooking")
|
||||
requiredClasses.Add("English")
|
||||
requiredClasses.Add("Math")
|
||||
requiredClasses.Add("Biology")
|
||||
|
||||
scienceSlice := []interface{}{"Biology", "Chemistry"}
|
||||
scienceClasses := NewSetFromSlice(scienceSlice)
|
||||
|
||||
electiveClasses := NewSet()
|
||||
electiveClasses.Add("Welding")
|
||||
electiveClasses.Add("Music")
|
||||
electiveClasses.Add("Automotive")
|
||||
|
||||
bonusClasses := NewSet()
|
||||
bonusClasses.Add("Go Programming")
|
||||
bonusClasses.Add("Python Programming")
|
||||
|
||||
//Show me all the available classes I can take
|
||||
allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses)
|
||||
fmt.Println(allClasses) //Set{English, Chemistry, Automotive, Cooking, Math, Biology, Welding, Music, Go Programming}
|
||||
|
||||
//Is cooking considered a science class?
|
||||
fmt.Println(scienceClasses.Contains("Cooking")) //false
|
||||
|
||||
//Show me all classes that are not science classes, since I hate science.
|
||||
fmt.Println(allClasses.Difference(scienceClasses)) //Set{English, Automotive, Cooking, Math, Welding, Music, Go Programming}
|
||||
|
||||
//Which science classes are also required classes?
|
||||
fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology}
|
||||
|
||||
//How many bonus classes do you offer?
|
||||
fmt.Println(bonusClasses.Cardinality()) //2
|
||||
|
||||
//Do you have the following classes? Welding, Automotive and English?
|
||||
fmt.Println(allClasses.ContainsAll("Welding", "Automotive", "English"))
|
||||
*/
|
||||
}
|
376
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/threadsafe_test.go
generated
vendored
376
libnetwork/Godeps/_workspace/src/github.com/deckarep/golang-set/threadsafe_test.go
generated
vendored
|
@ -1,376 +0,0 @@
|
|||
/*
|
||||
Open Source Initiative OSI - The MIT License (MIT):Licensing
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package mapset
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const N = 1000
|
||||
|
||||
func Test_AddConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for i := 0; i < len(ints); i++ {
|
||||
go func(i int) {
|
||||
s.Add(i)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
for _, i := range ints {
|
||||
if !s.Contains(i) {
|
||||
t.Errorf("Set is missing element: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CardinalityConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
elems := s.Cardinality()
|
||||
for i := 0; i < N; i++ {
|
||||
newElems := s.Cardinality()
|
||||
if newElems < elems {
|
||||
t.Errorf("Cardinality shrunk from %v to %v", elems, newElems)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
for i := 0; i < N; i++ {
|
||||
s.Add(rand.Int())
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_ClearConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for i := 0; i < len(ints); i++ {
|
||||
go func() {
|
||||
s.Clear()
|
||||
wg.Done()
|
||||
}()
|
||||
go func(i int) {
|
||||
s.Add(i)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_CloneConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for i := range ints {
|
||||
go func(i int) {
|
||||
s.Remove(i)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
s.Clone()
|
||||
}
|
||||
|
||||
func Test_ContainsConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.Contains(interfaces...)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_DifferenceConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.Difference(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_EqualConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.Equal(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_IntersectConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.Intersect(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_IsSubsetConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.IsSubset(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_IsSupersetConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.IsSuperset(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_IterConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
cs := make([]<-chan interface{}, 0)
|
||||
for _ = range ints {
|
||||
cs = append(cs, s.Iter())
|
||||
}
|
||||
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
for n := 0; n < len(ints)*N; {
|
||||
for _, d := range cs {
|
||||
select {
|
||||
case <-d:
|
||||
n++
|
||||
c <- nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
close(c)
|
||||
}()
|
||||
|
||||
for _ = range c {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RemoveConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for _, v := range ints {
|
||||
go func(i int) {
|
||||
s.Remove(i)
|
||||
wg.Done()
|
||||
}(v)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if s.Cardinality() != 0 {
|
||||
t.Errorf("Expected cardinality 0; got %v", s.Cardinality())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StringConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.String()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_SymmetricDifferenceConcurrent(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s, ss := NewSet(), NewSet()
|
||||
ints := rand.Perm(N)
|
||||
interfaces := make([]interface{}, 0)
|
||||
for _, v := range ints {
|
||||
s.Add(v)
|
||||
ss.Add(v)
|
||||
interfaces = append(interfaces, v)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _ = range ints {
|
||||
go func() {
|
||||
s.SymmetricDifference(ss)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func Test_ToSlice(t *testing.T) {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
s := NewSet()
|
||||
ints := rand.Perm(N)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(ints))
|
||||
for i := 0; i < len(ints); i++ {
|
||||
go func(i int) {
|
||||
s.Add(i)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
setAsSlice := s.ToSlice()
|
||||
if len(setAsSlice) != s.Cardinality() {
|
||||
t.Errorf("Set length is incorrect: %v", len(setAsSlice))
|
||||
}
|
||||
|
||||
for _, i := range setAsSlice {
|
||||
if !s.Contains(i) {
|
||||
t.Errorf("Set is missing element: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
23
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/types/blkiodev/blkio.go
generated
vendored
23
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/types/blkiodev/blkio.go
generated
vendored
|
@ -1,23 +0,0 @@
|
|||
package blkiodev
|
||||
|
||||
import "fmt"
|
||||
|
||||
// WeightDevice is a structure that hold device:weight pair
|
||||
type WeightDevice struct {
|
||||
Path string
|
||||
Weight uint16
|
||||
}
|
||||
|
||||
func (w *WeightDevice) String() string {
|
||||
return fmt.Sprintf("%s:%d", w.Path, w.Weight)
|
||||
}
|
||||
|
||||
// ThrottleDevice is a structure that hold device:rate_per_second pair
|
||||
type ThrottleDevice struct {
|
||||
Path string
|
||||
Rate uint64
|
||||
}
|
||||
|
||||
func (t *ThrottleDevice) String() string {
|
||||
return fmt.Sprintf("%s:%d", t.Path, t.Rate)
|
||||
}
|
34
libnetwork/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go
generated
vendored
34
libnetwork/Godeps/_workspace/src/github.com/docker/docker/opts/opts.go
generated
vendored
|
@ -36,7 +36,7 @@ func (opts *ListOpts) String() string {
|
|||
return fmt.Sprintf("%v", []string((*opts.values)))
|
||||
}
|
||||
|
||||
// Set validates if needed the input value and add it to the
|
||||
// Set validates if needed the input value and adds it to the
|
||||
// internal slice.
|
||||
func (opts *ListOpts) Set(value string) error {
|
||||
if opts.validator != nil {
|
||||
|
@ -240,3 +240,35 @@ func ValidateLabel(val string) (string, error) {
|
|||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// ValidateSysctl validates an sysctl and returns it.
|
||||
func ValidateSysctl(val string) (string, error) {
|
||||
validSysctlMap := map[string]bool{
|
||||
"kernel.msgmax": true,
|
||||
"kernel.msgmnb": true,
|
||||
"kernel.msgmni": true,
|
||||
"kernel.sem": true,
|
||||
"kernel.shmall": true,
|
||||
"kernel.shmmax": true,
|
||||
"kernel.shmmni": true,
|
||||
"kernel.shm_rmid_forced": true,
|
||||
}
|
||||
validSysctlPrefixes := []string{
|
||||
"net.",
|
||||
"fs.mqueue.",
|
||||
}
|
||||
arr := strings.Split(val, "=")
|
||||
if len(arr) < 2 {
|
||||
return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
|
||||
}
|
||||
if validSysctlMap[arr[0]] {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
for _, vp := range validSysctlPrefixes {
|
||||
if strings.HasPrefix(arr[0], vp) {
|
||||
return val, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
|
||||
}
|
||||
|
|
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/opts/opts_windows.go
generated
vendored
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/opts/opts_windows.go
generated
vendored
|
@ -1,10 +1,10 @@
|
|||
package opts
|
||||
|
||||
// TODO Windows. Identify bug in GOLang 1.5.1 and/or Windows Server 2016 TP4.
|
||||
// TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5.
|
||||
// @jhowardmsft, @swernli.
|
||||
//
|
||||
// On Windows, this mitigates a problem with the default options of running
|
||||
// a docker client against a local docker daemon on TP4.
|
||||
// a docker client against a local docker daemon on TP5.
|
||||
//
|
||||
// What was found that if the default host is "localhost", even if the client
|
||||
// (and daemon as this is local) is not physically on a network, and the DNS
|
||||
|
@ -35,7 +35,7 @@ package opts
|
|||
// time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1"
|
||||
//
|
||||
// We suspect this is either a bug introduced in GOLang 1.5.1, or that a change
|
||||
// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows TP4. In theory,
|
||||
// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory,
|
||||
// the Windows networking stack is supposed to resolve "localhost" internally,
|
||||
// without hitting DNS, or even reading the hosts file (which is why localhost
|
||||
// is commented out in the hosts file on Windows).
|
||||
|
@ -44,12 +44,12 @@ package opts
|
|||
// address does not cause the delay.
|
||||
//
|
||||
// This does not occur with the docker client built with 1.4.3 on the same
|
||||
// Windows TP4 build, regardless of whether the daemon is built using 1.5.1
|
||||
// Windows build, regardless of whether the daemon is built using 1.5.1
|
||||
// or 1.4.3. It does not occur on Linux. We also verified we see the same thing
|
||||
// on a cross-compiled Windows binary (from Linux).
|
||||
//
|
||||
// Final note: This is a mitigation, not a 'real' fix. It is still susceptible
|
||||
// to the delay in TP4 if a user were to do 'docker run -H=tcp://localhost:2375...'
|
||||
// to the delay if a user were to do 'docker run -H=tcp://localhost:2375...'
|
||||
// explicitly.
|
||||
|
||||
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. docker daemon -H tcp://:8080
|
||||
|
|
51
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/buffer.go
generated
vendored
Normal file
51
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/buffer.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var errBufferFull = errors.New("buffer is full")
|
||||
|
||||
type fixedBuffer struct {
|
||||
buf []byte
|
||||
pos int
|
||||
lastRead int
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) Write(p []byte) (int, error) {
|
||||
n := copy(b.buf[b.pos:cap(b.buf)], p)
|
||||
b.pos += n
|
||||
|
||||
if n < len(p) {
|
||||
if b.pos == cap(b.buf) {
|
||||
return n, errBufferFull
|
||||
}
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) Read(p []byte) (int, error) {
|
||||
n := copy(p, b.buf[b.lastRead:b.pos])
|
||||
b.lastRead += n
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) Len() int {
|
||||
return b.pos - b.lastRead
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) Cap() int {
|
||||
return cap(b.buf)
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) Reset() {
|
||||
b.pos = 0
|
||||
b.lastRead = 0
|
||||
b.buf = b.buf[:0]
|
||||
}
|
||||
|
||||
func (b *fixedBuffer) String() string {
|
||||
return string(b.buf[b.lastRead:b.pos])
|
||||
}
|
126
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go
generated
vendored
126
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/bytespipe.go
generated
vendored
|
@ -9,12 +9,19 @@ import (
|
|||
// maxCap is the highest capacity to use in byte slices that buffer data.
|
||||
const maxCap = 1e6
|
||||
|
||||
// minCap is the lowest capacity to use in byte slices that buffer data
|
||||
const minCap = 64
|
||||
|
||||
// blockThreshold is the minimum number of bytes in the buffer which will cause
|
||||
// a write to BytesPipe to block when allocating a new slice.
|
||||
const blockThreshold = 1e6
|
||||
|
||||
// ErrClosed is returned when Write is called on a closed BytesPipe.
|
||||
var ErrClosed = errors.New("write to closed BytesPipe")
|
||||
var (
|
||||
// ErrClosed is returned when Write is called on a closed BytesPipe.
|
||||
ErrClosed = errors.New("write to closed BytesPipe")
|
||||
|
||||
bufPools = make(map[int]*sync.Pool)
|
||||
)
|
||||
|
||||
// BytesPipe is io.ReadWriteCloser which works similarly to pipe(queue).
|
||||
// All written data may be read at most once. Also, BytesPipe allocates
|
||||
|
@ -23,22 +30,17 @@ var ErrClosed = errors.New("write to closed BytesPipe")
|
|||
type BytesPipe struct {
|
||||
mu sync.Mutex
|
||||
wait *sync.Cond
|
||||
buf [][]byte // slice of byte-slices of buffered data
|
||||
lastRead int // index in the first slice to a read point
|
||||
bufLen int // length of data buffered over the slices
|
||||
closeErr error // error to return from next Read. set to nil if not closed.
|
||||
buf []*fixedBuffer
|
||||
bufLen int
|
||||
closeErr error // error to return from next Read. set to nil if not closed.
|
||||
}
|
||||
|
||||
// NewBytesPipe creates new BytesPipe, initialized by specified slice.
|
||||
// If buf is nil, then it will be initialized with slice which cap is 64.
|
||||
// buf will be adjusted in a way that len(buf) == 0, cap(buf) == cap(buf).
|
||||
func NewBytesPipe(buf []byte) *BytesPipe {
|
||||
if cap(buf) == 0 {
|
||||
buf = make([]byte, 0, 64)
|
||||
}
|
||||
bp := &BytesPipe{
|
||||
buf: [][]byte{buf[:0]},
|
||||
}
|
||||
func NewBytesPipe() *BytesPipe {
|
||||
bp := &BytesPipe{}
|
||||
bp.buf = append(bp.buf, getBuffer(minCap))
|
||||
bp.wait = sync.NewCond(&bp.mu)
|
||||
return bp
|
||||
}
|
||||
|
@ -47,22 +49,31 @@ func NewBytesPipe(buf []byte) *BytesPipe {
|
|||
// It can allocate new []byte slices in a process of writing.
|
||||
func (bp *BytesPipe) Write(p []byte) (int, error) {
|
||||
bp.mu.Lock()
|
||||
defer bp.mu.Unlock()
|
||||
|
||||
written := 0
|
||||
loop0:
|
||||
for {
|
||||
if bp.closeErr != nil {
|
||||
bp.mu.Unlock()
|
||||
return written, ErrClosed
|
||||
}
|
||||
// write data to the last buffer
|
||||
b := bp.buf[len(bp.buf)-1]
|
||||
// copy data to the current empty allocated area
|
||||
n := copy(b[len(b):cap(b)], p)
|
||||
// increment buffered data length
|
||||
bp.bufLen += n
|
||||
// include written data in last buffer
|
||||
bp.buf[len(bp.buf)-1] = b[:len(b)+n]
|
||||
|
||||
if len(bp.buf) == 0 {
|
||||
bp.buf = append(bp.buf, getBuffer(64))
|
||||
}
|
||||
// get the last buffer
|
||||
b := bp.buf[len(bp.buf)-1]
|
||||
|
||||
n, err := b.Write(p)
|
||||
written += n
|
||||
bp.bufLen += n
|
||||
|
||||
// errBufferFull is an error we expect to get if the buffer is full
|
||||
if err != nil && err != errBufferFull {
|
||||
bp.wait.Broadcast()
|
||||
bp.mu.Unlock()
|
||||
return written, err
|
||||
}
|
||||
|
||||
// if there was enough room to write all then break
|
||||
if len(p) == n {
|
||||
|
@ -72,20 +83,23 @@ func (bp *BytesPipe) Write(p []byte) (int, error) {
|
|||
// more data: write to the next slice
|
||||
p = p[n:]
|
||||
|
||||
// block if too much data is still in the buffer
|
||||
// make sure the buffer doesn't grow too big from this write
|
||||
for bp.bufLen >= blockThreshold {
|
||||
bp.wait.Wait()
|
||||
if bp.closeErr != nil {
|
||||
continue loop0
|
||||
}
|
||||
}
|
||||
|
||||
// allocate slice that has twice the size of the last unless maximum reached
|
||||
nextCap := 2 * cap(bp.buf[len(bp.buf)-1])
|
||||
// add new byte slice to the buffers slice and continue writing
|
||||
nextCap := b.Cap() * 2
|
||||
if nextCap > maxCap {
|
||||
nextCap = maxCap
|
||||
}
|
||||
// add new byte slice to the buffers slice and continue writing
|
||||
bp.buf = append(bp.buf, make([]byte, 0, nextCap))
|
||||
bp.buf = append(bp.buf, getBuffer(nextCap))
|
||||
}
|
||||
bp.wait.Broadcast()
|
||||
bp.mu.Unlock()
|
||||
return written, nil
|
||||
}
|
||||
|
||||
|
@ -107,46 +121,60 @@ func (bp *BytesPipe) Close() error {
|
|||
return bp.CloseWithError(nil)
|
||||
}
|
||||
|
||||
func (bp *BytesPipe) len() int {
|
||||
return bp.bufLen - bp.lastRead
|
||||
}
|
||||
|
||||
// Read reads bytes from BytesPipe.
|
||||
// Data could be read only once.
|
||||
func (bp *BytesPipe) Read(p []byte) (n int, err error) {
|
||||
bp.mu.Lock()
|
||||
defer bp.mu.Unlock()
|
||||
if bp.len() == 0 {
|
||||
if bp.bufLen == 0 {
|
||||
if bp.closeErr != nil {
|
||||
bp.mu.Unlock()
|
||||
return 0, bp.closeErr
|
||||
}
|
||||
bp.wait.Wait()
|
||||
if bp.len() == 0 && bp.closeErr != nil {
|
||||
if bp.bufLen == 0 && bp.closeErr != nil {
|
||||
bp.mu.Unlock()
|
||||
return 0, bp.closeErr
|
||||
}
|
||||
}
|
||||
for {
|
||||
read := copy(p, bp.buf[0][bp.lastRead:])
|
||||
|
||||
for bp.bufLen > 0 {
|
||||
b := bp.buf[0]
|
||||
read, _ := b.Read(p) // ignore error since fixedBuffer doesn't really return an error
|
||||
n += read
|
||||
bp.lastRead += read
|
||||
if bp.len() == 0 {
|
||||
// we have read everything. reset to the beginning.
|
||||
bp.lastRead = 0
|
||||
bp.bufLen -= len(bp.buf[0])
|
||||
bp.buf[0] = bp.buf[0][:0]
|
||||
break
|
||||
bp.bufLen -= read
|
||||
|
||||
if b.Len() == 0 {
|
||||
// it's empty so return it to the pool and move to the next one
|
||||
returnBuffer(b)
|
||||
bp.buf[0] = nil
|
||||
bp.buf = bp.buf[1:]
|
||||
}
|
||||
// break if everything was read
|
||||
|
||||
if len(p) == read {
|
||||
break
|
||||
}
|
||||
// more buffered data and more asked. read from next slice.
|
||||
|
||||
p = p[read:]
|
||||
bp.lastRead = 0
|
||||
bp.bufLen -= len(bp.buf[0])
|
||||
bp.buf[0] = nil // throw away old slice
|
||||
bp.buf = bp.buf[1:] // switch to next
|
||||
}
|
||||
|
||||
bp.wait.Broadcast()
|
||||
bp.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func returnBuffer(b *fixedBuffer) {
|
||||
b.Reset()
|
||||
pool := bufPools[b.Cap()]
|
||||
if pool != nil {
|
||||
pool.Put(b)
|
||||
}
|
||||
}
|
||||
|
||||
func getBuffer(size int) *fixedBuffer {
|
||||
pool, ok := bufPools[size]
|
||||
if !ok {
|
||||
pool = &sync.Pool{New: func() interface{} { return &fixedBuffer{buf: make([]byte, 0, size)} }}
|
||||
bufPools[size] = pool
|
||||
}
|
||||
return pool.Get().(*fixedBuffer)
|
||||
}
|
||||
|
|
6
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/scheduler.go
generated
vendored
6
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/scheduler.go
generated
vendored
|
@ -1,6 +0,0 @@
|
|||
// +build !gccgo
|
||||
|
||||
package ioutils
|
||||
|
||||
func callSchedulerIfNecessary() {
|
||||
}
|
13
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/scheduler_gccgo.go
generated
vendored
13
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/scheduler_gccgo.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
// +build gccgo
|
||||
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func callSchedulerIfNecessary() {
|
||||
//allow or force Go scheduler to switch context, without explicitly
|
||||
//forcing this will make it hang when using gccgo implementation
|
||||
runtime.Gosched()
|
||||
}
|
27
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/listenbuffer/README.md
generated
vendored
27
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/listenbuffer/README.md
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
# listenbuffer
|
||||
|
||||
listenbuffer uses the kernel's listening backlog functionality to queue
|
||||
connections, allowing applications to start listening immediately and handle
|
||||
connections later. This is signaled by closing the activation channel passed to
|
||||
the constructor.
|
||||
|
||||
The maximum amount of queued connections depends on the configuration of your
|
||||
kernel (typically called SOMAXXCON) and cannot be configured in Go with the
|
||||
net package. See `src/net/sock_platform.go` in the Go tree or consult your
|
||||
kernel's manual.
|
||||
|
||||
activator := make(chan struct{})
|
||||
buffer, err := NewListenBuffer("tcp", "localhost:4000", activator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// will block until activator has been closed or is sent an event
|
||||
client, err := buffer.Accept()
|
||||
|
||||
Somewhere else in your application once it's been booted:
|
||||
|
||||
close(activator)
|
||||
|
||||
`buffer.Accept()` will return the first client in the kernel listening queue, or
|
||||
continue to block until a client connects or an error occurs.
|
76
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/listenbuffer/buffer.go
generated
vendored
76
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/listenbuffer/buffer.go
generated
vendored
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Package listenbuffer uses the kernel's listening backlog functionality to queue
|
||||
connections, allowing applications to start listening immediately and handle
|
||||
connections later. This is signaled by closing the activation channel passed to
|
||||
the constructor.
|
||||
|
||||
The maximum amount of queued connections depends on the configuration of your
|
||||
kernel (typically called SOMAXXCON) and cannot be configured in Go with the
|
||||
net package. See `src/net/sock_platform.go` in the Go tree or consult your
|
||||
kernel's manual.
|
||||
|
||||
activator := make(chan struct{})
|
||||
buffer, err := NewListenBuffer("tcp", "localhost:4000", activator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// will block until activator has been closed or is sent an event
|
||||
client, err := buffer.Accept()
|
||||
|
||||
Somewhere else in your application once it's been booted:
|
||||
|
||||
close(activator)
|
||||
|
||||
`buffer.Accept()` will return the first client in the kernel listening queue, or
|
||||
continue to block until a client connects or an error occurs.
|
||||
*/
|
||||
package listenbuffer
|
||||
|
||||
import "net"
|
||||
|
||||
// NewListenBuffer returns a net.Listener listening on addr with the protocol
|
||||
// passed. The channel passed is used to activate the listenbuffer when the
|
||||
// caller is ready to accept connections.
|
||||
func NewListenBuffer(proto, addr string, activate <-chan struct{}) (net.Listener, error) {
|
||||
wrapped, err := net.Listen(proto, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &defaultListener{
|
||||
wrapped: wrapped,
|
||||
activate: activate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// defaultListener is the buffered wrapper around the net.Listener
|
||||
type defaultListener struct {
|
||||
wrapped net.Listener // The net.Listener wrapped by listenbuffer
|
||||
ready bool // Whether the listenbuffer has been activated
|
||||
activate <-chan struct{} // Channel to control activation of the listenbuffer
|
||||
}
|
||||
|
||||
// Close closes the wrapped socket.
|
||||
func (l *defaultListener) Close() error {
|
||||
return l.wrapped.Close()
|
||||
}
|
||||
|
||||
// Addr returns the listening address of the wrapped socket.
|
||||
func (l *defaultListener) Addr() net.Addr {
|
||||
return l.wrapped.Addr()
|
||||
}
|
||||
|
||||
// Accept returns a client connection on the wrapped socket if the listen buffer
|
||||
// has been activated. To active the listenbuffer the activation channel passed
|
||||
// to NewListenBuffer must have been closed or sent an event.
|
||||
func (l *defaultListener) Accept() (net.Conn, error) {
|
||||
// if the listen has been told it is ready then we can go ahead and
|
||||
// start returning connections
|
||||
if l.ready {
|
||||
return l.wrapped.Accept()
|
||||
}
|
||||
<-l.activate
|
||||
l.ready = true
|
||||
return l.Accept()
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package listenbuffer
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListenBufferAllowsAcceptingWhenActivated(t *testing.T) {
|
||||
lock := make(chan struct{})
|
||||
buffer, err := NewListenBuffer("tcp", "", lock)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to create listen buffer: ", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
conn, err := net.Dial("tcp", buffer.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal("Client failed to establish connection to server: ", err)
|
||||
}
|
||||
|
||||
conn.Write([]byte("ping"))
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
close(lock)
|
||||
|
||||
client, err := buffer.Accept()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to accept client: ", err)
|
||||
}
|
||||
|
||||
response, err := ioutil.ReadAll(client)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to read from client: ", err)
|
||||
}
|
||||
|
||||
if string(response) != "ping" {
|
||||
t.Fatal("Expected to receive ping from client, received: ", string(response))
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
// Utsname represents the system name structure.
|
||||
// It is passthgrouh for syscall.Utsname in order to make it portable with
|
||||
// It is passthrough for syscall.Utsname in order to make it portable with
|
||||
// other platforms where it is not available.
|
||||
type Utsname syscall.Utsname
|
||||
|
||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -118,6 +119,7 @@ func readPluginJSONInfo(name, path string) (*Plugin, error) {
|
|||
if len(p.TLSConfig.CAFile) == 0 {
|
||||
p.TLSConfig.InsecureSkipVerify = true
|
||||
}
|
||||
p.activateWait = sync.NewCond(&sync.Mutex{})
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/plugins.go
generated
vendored
|
@ -67,7 +67,7 @@ type Plugin struct {
|
|||
|
||||
// error produced by activation
|
||||
activateErr error
|
||||
// specifies if the activation sequence is completed (not if it is sucessful or not)
|
||||
// specifies if the activation sequence is completed (not if it is successful or not)
|
||||
activated bool
|
||||
// wait for activation to finish
|
||||
activateWait *sync.Cond
|
||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
|
@ -12,7 +12,7 @@ var registeredInitializers = make(map[string]func())
|
|||
// Register adds an initialization func under the specified name
|
||||
func Register(name string, initializer func()) {
|
||||
if _, exists := registeredInitializers[name]; exists {
|
||||
panic(fmt.Sprintf("reexec func already registred under name %q", name))
|
||||
panic(fmt.Sprintf("reexec func already registered under name %q", name))
|
||||
}
|
||||
|
||||
registeredInitializers[name] = initializer
|
||||
|
|
0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/sockets/README.md
generated
vendored
0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/sockets/README.md
generated
vendored
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue