mirror of https://github.com/docker/docs.git
commit
45d38fd31b
|
@ -123,6 +123,10 @@
|
||||||
"ImportPath": "golang.org/x/oauth2",
|
"ImportPath": "golang.org/x/oauth2",
|
||||||
"Rev": "038cb4adce85ed41e285c2e7cc6221a92bfa44aa"
|
"Rev": "038cb4adce85ed41e285c2e7cc6221a92bfa44aa"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/sys/windows/registry",
|
||||||
|
"Rev": "d9157a9621b69ad1d8d77a1933590c416593f24f"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/api/compute/v1",
|
"ImportPath": "google.golang.org/api/compute/v1",
|
||||||
"Rev": "a09229c13c2f13bbdedf7b31b506cad4c83ef3bf"
|
"Rev": "a09229c13c2f13bbdedf7b31b506cad4c83ef3bf"
|
||||||
|
@ -138,10 +142,6 @@
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud/internal",
|
"ImportPath": "google.golang.org/cloud/internal",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/sys",
|
|
||||||
"Rev": "d9157a9621b69ad1d8d77a1933590c416593f24f"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNextBackOffMillis(t *testing.T) {
|
|
||||||
subtestNextBackOff(t, 0, new(ZeroBackOff))
|
|
||||||
subtestNextBackOff(t, Stop, new(StopBackOff))
|
|
||||||
}
|
|
||||||
|
|
||||||
func subtestNextBackOff(t *testing.T, expectedValue time.Duration, backOffPolicy BackOff) {
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
next := backOffPolicy.NextBackOff()
|
|
||||||
if next != expectedValue {
|
|
||||||
t.Errorf("got: %d expected: %d", next, expectedValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConstantBackOff(t *testing.T) {
|
|
||||||
backoff := NewConstantBackOff(time.Second)
|
|
||||||
if backoff.NextBackOff() != time.Second {
|
|
||||||
t.Error("invalid interval")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBackOff(t *testing.T) {
|
|
||||||
var (
|
|
||||||
testInitialInterval = 500 * time.Millisecond
|
|
||||||
testRandomizationFactor = 0.1
|
|
||||||
testMultiplier = 2.0
|
|
||||||
testMaxInterval = 5 * time.Second
|
|
||||||
testMaxElapsedTime = 15 * time.Minute
|
|
||||||
)
|
|
||||||
|
|
||||||
exp := NewExponentialBackOff()
|
|
||||||
exp.InitialInterval = testInitialInterval
|
|
||||||
exp.RandomizationFactor = testRandomizationFactor
|
|
||||||
exp.Multiplier = testMultiplier
|
|
||||||
exp.MaxInterval = testMaxInterval
|
|
||||||
exp.MaxElapsedTime = testMaxElapsedTime
|
|
||||||
exp.Reset()
|
|
||||||
|
|
||||||
var expectedResults = []time.Duration{500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000}
|
|
||||||
for i, d := range expectedResults {
|
|
||||||
expectedResults[i] = d * time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, expected := range expectedResults {
|
|
||||||
assertEquals(t, expected, exp.currentInterval)
|
|
||||||
// Assert that the next back off falls in the expected range.
|
|
||||||
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
|
||||||
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
|
||||||
var actualInterval = exp.NextBackOff()
|
|
||||||
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
|
|
||||||
t.Error("error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetRandomizedInterval(t *testing.T) {
|
|
||||||
// 33% chance of being 1.
|
|
||||||
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0, 2))
|
|
||||||
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0.33, 2))
|
|
||||||
// 33% chance of being 2.
|
|
||||||
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.34, 2))
|
|
||||||
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.66, 2))
|
|
||||||
// 33% chance of being 3.
|
|
||||||
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.67, 2))
|
|
||||||
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.99, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestClock struct {
|
|
||||||
i time.Duration
|
|
||||||
start time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TestClock) Now() time.Time {
|
|
||||||
t := c.start.Add(c.i)
|
|
||||||
c.i += time.Second
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetElapsedTime(t *testing.T) {
|
|
||||||
var exp = NewExponentialBackOff()
|
|
||||||
exp.Clock = &TestClock{}
|
|
||||||
exp.Reset()
|
|
||||||
|
|
||||||
var elapsedTime = exp.GetElapsedTime()
|
|
||||||
if elapsedTime != time.Second {
|
|
||||||
t.Errorf("elapsedTime=%d", elapsedTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMaxElapsedTime(t *testing.T) {
|
|
||||||
var exp = NewExponentialBackOff()
|
|
||||||
exp.Clock = &TestClock{start: time.Time{}.Add(10000 * time.Second)}
|
|
||||||
if exp.NextBackOff() != Stop {
|
|
||||||
t.Error("error2")
|
|
||||||
}
|
|
||||||
// Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater
|
|
||||||
// than the max elapsed time.
|
|
||||||
exp.startTime = time.Time{}
|
|
||||||
assertEquals(t, Stop, exp.NextBackOff())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBackOffOverflow(t *testing.T) {
|
|
||||||
var (
|
|
||||||
testInitialInterval time.Duration = math.MaxInt64 / 2
|
|
||||||
testMaxInterval time.Duration = math.MaxInt64
|
|
||||||
testMultiplier float64 = 2.1
|
|
||||||
)
|
|
||||||
|
|
||||||
exp := NewExponentialBackOff()
|
|
||||||
exp.InitialInterval = testInitialInterval
|
|
||||||
exp.Multiplier = testMultiplier
|
|
||||||
exp.MaxInterval = testMaxInterval
|
|
||||||
exp.Reset()
|
|
||||||
|
|
||||||
exp.NextBackOff()
|
|
||||||
// Assert that when an overflow is possible the current varerval time.Duration is set to the max varerval time.Duration .
|
|
||||||
assertEquals(t, testMaxInterval, exp.currentInterval)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertEquals(t *testing.T, expected, value time.Duration) {
|
|
||||||
if expected != value {
|
|
||||||
t.Errorf("got: %d, expected: %d", value, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRetry(t *testing.T) {
|
|
||||||
const successOn = 3
|
|
||||||
var i = 0
|
|
||||||
|
|
||||||
// This function is successfull on "successOn" calls.
|
|
||||||
f := func() error {
|
|
||||||
i++
|
|
||||||
log.Printf("function is called %d. time\n", i)
|
|
||||||
|
|
||||||
if i == successOn {
|
|
||||||
log.Println("OK")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("error")
|
|
||||||
return errors.New("error")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Retry(f, NewExponentialBackOff())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %s", err.Error())
|
|
||||||
}
|
|
||||||
if i != successOn {
|
|
||||||
t.Errorf("invalid number of retries: %d", i)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTicker(t *testing.T) {
|
|
||||||
const successOn = 3
|
|
||||||
var i = 0
|
|
||||||
|
|
||||||
// This function is successfull on "successOn" calls.
|
|
||||||
f := func() error {
|
|
||||||
i++
|
|
||||||
log.Printf("function is called %d. time\n", i)
|
|
||||||
|
|
||||||
if i == successOn {
|
|
||||||
log.Println("OK")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("error")
|
|
||||||
return errors.New("error")
|
|
||||||
}
|
|
||||||
|
|
||||||
b := NewExponentialBackOff()
|
|
||||||
ticker := NewTicker(b)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
for _ = range ticker.C {
|
|
||||||
if err = f(); err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %s", err.Error())
|
|
||||||
}
|
|
||||||
if i != successOn {
|
|
||||||
t.Errorf("invalid number of retries: %d", i)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestActionRequest_String(t *testing.T) {
|
|
||||||
action := &ActionRequest{
|
|
||||||
Type: "transfer",
|
|
||||||
Params: map[string]interface{}{"key-1": "value-1"},
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := action.String()
|
|
||||||
expected := `godo.ActionRequest{Type:"transfer", Params:map[key-1:value-1]}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Action.Stringify returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAction_ActionsServiceOpImplementsActionsService(t *testing.T) {
|
|
||||||
if !Implements((*ActionsService)(nil), new(ActionsServiceOp)) {
|
|
||||||
t.Error("ActionsServiceOp does not implement ActionsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAction_List(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprint(w, `{"actions": [{"id":1},{"id":2}]}`)
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
})
|
|
||||||
|
|
||||||
actions, _, err := client.Actions.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Action{{ID: 1}, {ID: 2}}
|
|
||||||
if len(actions) != len(expected) || actions[0].ID != expected[0].ID || actions[1].ID != expected[1].ID {
|
|
||||||
t.Fatalf("unexpected response")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAction_ListActionMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprint(w, `{"actions": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/droplets/?page=2"}}}`)
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Actions.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAction_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"actions": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/actions/?page=3",
|
|
||||||
"prev":"http://example.com/v2/actions/?page=1",
|
|
||||||
"last":"http://example.com/v2/actions/?page=3",
|
|
||||||
"first":"http://example.com/v2/actions/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Actions.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAction_Get(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/actions/12345", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprint(w, `{"action": {"id":12345}}`)
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.Actions.Get(12345)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if action.ID != 12345 {
|
|
||||||
t.Fatalf("unexpected response")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAction_String(t *testing.T) {
|
|
||||||
pt, err := time.Parse(time.RFC3339, "2014-05-08T20:36:47Z")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
startedAt := &Timestamp{
|
|
||||||
Time: pt,
|
|
||||||
}
|
|
||||||
action := &Action{
|
|
||||||
ID: 1,
|
|
||||||
Status: "in-progress",
|
|
||||||
Type: "transfer",
|
|
||||||
StartedAt: startedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := action.String()
|
|
||||||
expected := `godo.Action{ID:1, Status:"in-progress", Type:"transfer", ` +
|
|
||||||
`StartedAt:godo.Timestamp{2014-05-08 20:36:47 +0000 UTC}, ` +
|
|
||||||
`ResourceID:0, ResourceType:""}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Action.Stringify returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,345 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAction_DomainsServiceOpImplementsDomainsService(t *testing.T) {
|
|
||||||
if !Implements((*DomainsService)(nil), new(DomainsServiceOp)) {
|
|
||||||
t.Error("DomainsServiceOp does not implement DomainsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_ListDomains(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"domains": [{"name":"foo.com"},{"name":"bar.com"}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
domains, _, err := client.Domains.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Domain{{Name: "foo.com"}, {Name: "bar.com"}}
|
|
||||||
if !reflect.DeepEqual(domains, expected) {
|
|
||||||
t.Errorf("Domains.List returned %+v, expected %+v", domains, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_ListDomainsMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"domains": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/domains/?page=2"}}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Domains.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"domains": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/domains/?page=3",
|
|
||||||
"prev":"http://example.com/v2/domains/?page=1",
|
|
||||||
"last":"http://example.com/v2/domains/?page=3",
|
|
||||||
"first":"http://example.com/v2/domains/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Domains.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_GetDomain(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"domain":{"name":"example.com"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
domains, _, err := client.Domains.Get("example.com")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("domain.Get returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DomainRoot{Domain: &Domain{Name: "example.com"}}
|
|
||||||
if !reflect.DeepEqual(domains, expected) {
|
|
||||||
t.Errorf("domains.Get returned %+v, expected %+v", domains, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_Create(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
createRequest := &DomainCreateRequest{
|
|
||||||
Name: "example.com",
|
|
||||||
IPAddress: "127.0.0.1",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(DomainCreateRequest)
|
|
||||||
err := json.NewDecoder(r.Body).Decode(v)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, createRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
dr := DomainRoot{&Domain{Name: v.Name}}
|
|
||||||
b, err := json.Marshal(dr)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, string(b))
|
|
||||||
})
|
|
||||||
|
|
||||||
domain, _, err := client.Domains.Create(createRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.Create returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DomainRoot{Domain: &Domain{Name: "example.com"}}
|
|
||||||
if !reflect.DeepEqual(domain, expected) {
|
|
||||||
t.Errorf("Domains.Create returned %+v, expected %+v", domain, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_Destroy(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "DELETE")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := client.Domains.Delete("example.com")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.Delete returned error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_AllRecordsForDomainName(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"domain_records":[{"id":1},{"id":2}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
records, _, err := client.Domains.Records("example.com", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []DomainRecord{{ID: 1}, {ID: 2}}
|
|
||||||
if !reflect.DeepEqual(records, expected) {
|
|
||||||
t.Errorf("Domains.List returned %+v, expected %+v", records, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_AllRecordsForDomainName_PerPage(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
perPage := r.URL.Query().Get("per_page")
|
|
||||||
if perPage != "2" {
|
|
||||||
t.Fatalf("expected '2', got '%s'", perPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, `{"domain_records":[{"id":1},{"id":2}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
dro := &ListOptions{PerPage: 2}
|
|
||||||
records, _, err := client.Domains.Records("example.com", dro)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []DomainRecord{{ID: 1}, {ID: 2}}
|
|
||||||
if !reflect.DeepEqual(records, expected) {
|
|
||||||
t.Errorf("Domains.List returned %+v, expected %+v", records, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_GetRecordforDomainName(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records/1", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"domain_record":{"id":1}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
record, _, err := client.Domains.Record("example.com", 1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.GetRecord returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DomainRecord{ID: 1}
|
|
||||||
if !reflect.DeepEqual(record, expected) {
|
|
||||||
t.Errorf("Domains.GetRecord returned %+v, expected %+v", record, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_DeleteRecordForDomainName(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records/1", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "DELETE")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := client.Domains.DeleteRecord("example.com", 1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.RecordDelete returned error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_CreateRecordForDomainName(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
createRequest := &DomainRecordEditRequest{
|
|
||||||
Type: "CNAME",
|
|
||||||
Name: "example",
|
|
||||||
Data: "@",
|
|
||||||
Priority: 10,
|
|
||||||
Port: 10,
|
|
||||||
Weight: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records",
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(DomainRecordEditRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, createRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"domain_record": {"id":1}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
record, _, err := client.Domains.CreateRecord("example.com", createRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.CreateRecord returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DomainRecord{ID: 1}
|
|
||||||
if !reflect.DeepEqual(record, expected) {
|
|
||||||
t.Errorf("Domains.CreateRecord returned %+v, expected %+v", record, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomains_EditRecordForDomainName(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
editRequest := &DomainRecordEditRequest{
|
|
||||||
Type: "CNAME",
|
|
||||||
Name: "example",
|
|
||||||
Data: "@",
|
|
||||||
Priority: 10,
|
|
||||||
Port: 10,
|
|
||||||
Weight: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/domains/example.com/records/1", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(DomainRecordEditRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "PUT")
|
|
||||||
if !reflect.DeepEqual(v, editRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, editRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"id":1}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
record, _, err := client.Domains.EditRecord("example.com", 1, editRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Domains.EditRecord returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DomainRecord{ID: 1}
|
|
||||||
if !reflect.DeepEqual(record, expected) {
|
|
||||||
t.Errorf("Domains.EditRecord returned %+v, expected %+v", record, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomainRecord_String(t *testing.T) {
|
|
||||||
record := &DomainRecord{
|
|
||||||
ID: 1,
|
|
||||||
Type: "CNAME",
|
|
||||||
Name: "example",
|
|
||||||
Data: "@",
|
|
||||||
Priority: 10,
|
|
||||||
Port: 10,
|
|
||||||
Weight: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := record.String()
|
|
||||||
expected := `godo.DomainRecord{ID:1, Type:"CNAME", Name:"example", Data:"@", Priority:10, Port:10, Weight:10}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("DomainRecord.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDomainRecordEditRequest_String(t *testing.T) {
|
|
||||||
record := &DomainRecordEditRequest{
|
|
||||||
Type: "CNAME",
|
|
||||||
Name: "example",
|
|
||||||
Data: "@",
|
|
||||||
Priority: 10,
|
|
||||||
Port: 10,
|
|
||||||
Weight: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := record.String()
|
|
||||||
expected := `godo.DomainRecordEditRequest{Type:"CNAME", Name:"example", Data:"@", Priority:10, Port:10, Weight:10}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("DomainRecordEditRequest.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,305 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDropletActions_DropletActionsServiceOpImplementsDropletActionsService(t *testing.T) {
|
|
||||||
if !Implements((*DropletActionsService)(nil), new(DropletActionsServiceOp)) {
|
|
||||||
t.Error("DropletActionsServiceOp does not implement DropletActionsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletActions_Shutdown(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "shutdown",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Shutdown(1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_PowerOff(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "power_off",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.PowerOff(1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_PowerOn(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "power_on",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.PowerOn(1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.PowerOn returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.PowerOn returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_Reboot(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "reboot",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Reboot(1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_Restore(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
options := map[string]interface{}{
|
|
||||||
"image": float64(1),
|
|
||||||
}
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "restore",
|
|
||||||
Params: options,
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Restore(1, 1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_Resize(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
options := map[string]interface{}{
|
|
||||||
"size": "1024mb",
|
|
||||||
}
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "resize",
|
|
||||||
Params: options,
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Resize(1, "1024mb")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_Rename(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
options := map[string]interface{}{
|
|
||||||
"name": "Droplet-Name",
|
|
||||||
}
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "rename",
|
|
||||||
Params: options,
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Rename(1, "Droplet-Name")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletAction_PowerCycle(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
request := &ActionRequest{
|
|
||||||
Type: "power_cycle",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, request) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.PowerCycle(1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Shutdown returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropletActions_Get(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/123/actions/456", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.DropletActions.Get(123, 456)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("DropletActions.Get returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("DropletActions.Get returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,242 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAction_DropletsServiceOpImplementsActionService(t *testing.T) {
|
|
||||||
if !Implements((*DropletsService)(nil), new(DropletsServiceOp)) {
|
|
||||||
t.Error("DropletsServiceOp does not implement DropletsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_ListDroplets(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"droplets": [{"id":1},{"id":2}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
droplets, _, err := client.Droplets.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Droplets.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Droplet{{ID: 1}, {ID: 2}}
|
|
||||||
if !reflect.DeepEqual(droplets, expected) {
|
|
||||||
t.Errorf("Droplets.List returned %+v, expected %+v", droplets, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_ListDropletsMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
|
|
||||||
dr := dropletsRoot{
|
|
||||||
Droplets: []Droplet{
|
|
||||||
Droplet{ID: 1},
|
|
||||||
Droplet{ID: 2},
|
|
||||||
},
|
|
||||||
Links: &Links{
|
|
||||||
Pages: &Pages{Next: "http://example.com/v2/droplets/?page=2"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(dr)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, string(b))
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Droplets.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"droplets": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/droplets/?page=3",
|
|
||||||
"prev":"http://example.com/v2/droplets/?page=1",
|
|
||||||
"last":"http://example.com/v2/droplets/?page=3",
|
|
||||||
"first":"http://example.com/v2/droplets/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Droplets.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_GetDroplet(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/12345", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"droplet":{"id":12345}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
droplets, _, err := client.Droplets.Get(12345)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Droplet.Get returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &DropletRoot{Droplet: &Droplet{ID: 12345}}
|
|
||||||
if !reflect.DeepEqual(droplets, expected) {
|
|
||||||
t.Errorf("Droplets.Get returned %+v, expected %+v", droplets, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_Create(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
createRequest := &DropletCreateRequest{
|
|
||||||
Name: "name",
|
|
||||||
Region: "region",
|
|
||||||
Size: "size",
|
|
||||||
Image: "1",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(DropletCreateRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, createRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"droplet":{"id":1}, "links":{"actions": [{"id": 1, "href": "http://example.com", "rel": "create"}]}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
root, resp, err := client.Droplets.Create(createRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Droplets.Create returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if id := root.Droplet.ID; id != 1 {
|
|
||||||
t.Errorf("expected id '%d', received '%d'", 1, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if a := resp.Links.Actions[0]; a.ID != 1 {
|
|
||||||
t.Errorf("expected action id '%d', received '%d'", 1, a.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplets_Destroy(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/droplets/12345", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "DELETE")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := client.Droplets.Delete(12345)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Droplet.Delete returned error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNetwork_String(t *testing.T) {
|
|
||||||
network := &Network{
|
|
||||||
IPAddress: "192.168.1.2",
|
|
||||||
Netmask: "255.255.255.0",
|
|
||||||
Gateway: "192.168.1.1",
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := network.String()
|
|
||||||
expected := `godo.Network{IPAddress:"192.168.1.2", Netmask:"255.255.255.0", Gateway:"192.168.1.1", Type:""}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Distribution.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDroplet_String(t *testing.T) {
|
|
||||||
|
|
||||||
region := &Region{
|
|
||||||
Slug: "region",
|
|
||||||
Name: "Region",
|
|
||||||
Sizes: []string{"1", "2"},
|
|
||||||
Available: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
image := &Image{
|
|
||||||
ID: 1,
|
|
||||||
Name: "Image",
|
|
||||||
Distribution: "Ubuntu",
|
|
||||||
Slug: "image",
|
|
||||||
Public: true,
|
|
||||||
Regions: []string{"one", "two"},
|
|
||||||
}
|
|
||||||
|
|
||||||
size := &Size{
|
|
||||||
Slug: "size",
|
|
||||||
PriceMonthly: 123,
|
|
||||||
PriceHourly: 456,
|
|
||||||
Regions: []string{"1", "2"},
|
|
||||||
}
|
|
||||||
network := &Network{
|
|
||||||
IPAddress: "192.168.1.2",
|
|
||||||
Netmask: "255.255.255.0",
|
|
||||||
Gateway: "192.168.1.1",
|
|
||||||
}
|
|
||||||
networks := &Networks{
|
|
||||||
V4: []Network{*network},
|
|
||||||
}
|
|
||||||
|
|
||||||
droplet := &Droplet{
|
|
||||||
ID: 1,
|
|
||||||
Name: "droplet",
|
|
||||||
Memory: 123,
|
|
||||||
Vcpus: 456,
|
|
||||||
Disk: 789,
|
|
||||||
Region: region,
|
|
||||||
Image: image,
|
|
||||||
Size: size,
|
|
||||||
BackupIDs: []int{1},
|
|
||||||
SnapshotIDs: []int{1},
|
|
||||||
ActionIDs: []int{1},
|
|
||||||
Locked: false,
|
|
||||||
Status: "active",
|
|
||||||
Networks: networks,
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := droplet.String()
|
|
||||||
expected := `godo.Droplet{ID:1, Name:"droplet", Memory:123, Vcpus:456, Disk:789, Region:godo.Region{Slug:"region", Name:"Region", Sizes:["1" "2"], Available:true}, Image:godo.Image{ID:1, Name:"Image", Distribution:"Ubuntu", Slug:"image", Public:true, Regions:["one" "two"]}, Size:godo.Size{Slug:"size", Memory:0, Vcpus:0, Disk:0, PriceMonthly:123, PriceHourly:456, Regions:["1" "2"]}, BackupIDs:[1], SnapshotIDs:[1], Locked:false, Status:"active", Networks:godo.Networks{V4:[godo.Network{IPAddress:"192.168.1.2", Netmask:"255.255.255.0", Gateway:"192.168.1.1", Type:""}]}, ActionIDs:[1]}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Droplet.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,325 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mux *http.ServeMux
|
|
||||||
|
|
||||||
client *Client
|
|
||||||
|
|
||||||
server *httptest.Server
|
|
||||||
)
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
mux = http.NewServeMux()
|
|
||||||
server = httptest.NewServer(mux)
|
|
||||||
|
|
||||||
client = NewClient(nil)
|
|
||||||
url, _ := url.Parse(server.URL)
|
|
||||||
client.BaseURL = url
|
|
||||||
}
|
|
||||||
|
|
||||||
func teardown() {
|
|
||||||
server.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMethod(t *testing.T, r *http.Request, expected string) {
|
|
||||||
if expected != r.Method {
|
|
||||||
t.Errorf("Request method = %v, expected %v", r.Method, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type values map[string]string
|
|
||||||
|
|
||||||
func testFormValues(t *testing.T, r *http.Request, values values) {
|
|
||||||
expected := url.Values{}
|
|
||||||
for k, v := range values {
|
|
||||||
expected.Add(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
r.ParseForm()
|
|
||||||
if !reflect.DeepEqual(expected, r.Form) {
|
|
||||||
t.Errorf("Request parameters = %v, expected %v", r.Form, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testURLParseError(t *testing.T, err error) {
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error to be returned")
|
|
||||||
}
|
|
||||||
if err, ok := err.(*url.Error); !ok || err.Op != "parse" {
|
|
||||||
t.Errorf("Expected URL parse error, got %+v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
|
||||||
c := NewClient(nil)
|
|
||||||
if c.BaseURL.String() != defaultBaseURL {
|
|
||||||
t.Errorf("NewClient BaseURL = %v, expected %v", c.BaseURL.String(), defaultBaseURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.UserAgent != userAgent {
|
|
||||||
t.Errorf("NewClick UserAgent = %v, expected %v", c.UserAgent, userAgent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRequest(t *testing.T) {
|
|
||||||
c := NewClient(nil)
|
|
||||||
|
|
||||||
inURL, outURL := "/foo", defaultBaseURL+"foo"
|
|
||||||
inBody, outBody := &DropletCreateRequest{Name: "l"},
|
|
||||||
`{"name":"l","region":"","size":"","image":"",`+
|
|
||||||
`"ssh_keys":null,"backups":false,"ipv6":false,`+
|
|
||||||
`"private_networking":false,"user_data":""}`+"\n"
|
|
||||||
req, _ := c.NewRequest("GET", inURL, inBody)
|
|
||||||
|
|
||||||
// test relative URL was expanded
|
|
||||||
if req.URL.String() != outURL {
|
|
||||||
t.Errorf("NewRequest(%v) URL = %v, expected %v", inURL, req.URL, outURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// test body was JSON encoded
|
|
||||||
body, _ := ioutil.ReadAll(req.Body)
|
|
||||||
if string(body) != outBody {
|
|
||||||
t.Errorf("NewRequest(%v)Body = %v, expected %v", inBody, string(body), outBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
// test default user-agent is attached to the request
|
|
||||||
userAgent := req.Header.Get("User-Agent")
|
|
||||||
if c.UserAgent != userAgent {
|
|
||||||
t.Errorf("NewRequest() User-Agent = %v, expected %v", userAgent, c.UserAgent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRequest_invalidJSON(t *testing.T) {
|
|
||||||
c := NewClient(nil)
|
|
||||||
|
|
||||||
type T struct {
|
|
||||||
A map[int]interface{}
|
|
||||||
}
|
|
||||||
_, err := c.NewRequest("GET", "/", &T{})
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Expected error to be returned.")
|
|
||||||
}
|
|
||||||
if err, ok := err.(*json.UnsupportedTypeError); !ok {
|
|
||||||
t.Errorf("Expected a JSON error; got %#v.", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRequest_badURL(t *testing.T) {
|
|
||||||
c := NewClient(nil)
|
|
||||||
_, err := c.NewRequest("GET", ":", nil)
|
|
||||||
testURLParseError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDo(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
type foo struct {
|
|
||||||
A string
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if m := "GET"; m != r.Method {
|
|
||||||
t.Errorf("Request method = %v, expected %v", r.Method, m)
|
|
||||||
}
|
|
||||||
fmt.Fprint(w, `{"A":"a"}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
req, _ := client.NewRequest("GET", "/", nil)
|
|
||||||
body := new(foo)
|
|
||||||
client.Do(req, body)
|
|
||||||
|
|
||||||
expected := &foo{"a"}
|
|
||||||
if !reflect.DeepEqual(body, expected) {
|
|
||||||
t.Errorf("Response body = %v, expected %v", body, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDo_httpError(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
http.Error(w, "Bad Request", 400)
|
|
||||||
})
|
|
||||||
|
|
||||||
req, _ := client.NewRequest("GET", "/", nil)
|
|
||||||
_, err := client.Do(req, nil)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Expected HTTP 400 error.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test handling of an error caused by the internal http client's Do()
|
|
||||||
// function.
|
|
||||||
func TestDo_redirectLoop(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
http.Redirect(w, r, "/", http.StatusFound)
|
|
||||||
})
|
|
||||||
|
|
||||||
req, _ := client.NewRequest("GET", "/", nil)
|
|
||||||
_, err := client.Do(req, nil)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Expected error to be returned.")
|
|
||||||
}
|
|
||||||
if err, ok := err.(*url.Error); !ok {
|
|
||||||
t.Errorf("Expected a URL error; got %#v.", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckResponse(t *testing.T) {
|
|
||||||
res := &http.Response{
|
|
||||||
Request: &http.Request{},
|
|
||||||
StatusCode: http.StatusBadRequest,
|
|
||||||
Body: ioutil.NopCloser(strings.NewReader(`{"message":"m",
|
|
||||||
"errors": [{"resource": "r", "field": "f", "code": "c"}]}`)),
|
|
||||||
}
|
|
||||||
err := CheckResponse(res).(*ErrorResponse)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected error response.")
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &ErrorResponse{
|
|
||||||
Response: res,
|
|
||||||
Message: "m",
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(err, expected) {
|
|
||||||
t.Errorf("Error = %#v, expected %#v", err, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure that we properly handle API errors that do not contain a response
|
|
||||||
// body
|
|
||||||
func TestCheckResponse_noBody(t *testing.T) {
|
|
||||||
res := &http.Response{
|
|
||||||
Request: &http.Request{},
|
|
||||||
StatusCode: http.StatusBadRequest,
|
|
||||||
Body: ioutil.NopCloser(strings.NewReader("")),
|
|
||||||
}
|
|
||||||
err := CheckResponse(res).(*ErrorResponse)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error response.")
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &ErrorResponse{
|
|
||||||
Response: res,
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(err, expected) {
|
|
||||||
t.Errorf("Error = %#v, expected %#v", err, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorResponse_Error(t *testing.T) {
|
|
||||||
res := &http.Response{Request: &http.Request{}}
|
|
||||||
err := ErrorResponse{Message: "m", Response: res}
|
|
||||||
if err.Error() == "" {
|
|
||||||
t.Errorf("Expected non-empty ErrorResponse.Error()")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDo_rateLimit(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Add(headerRateLimit, "60")
|
|
||||||
w.Header().Add(headerRateRemaining, "59")
|
|
||||||
w.Header().Add(headerRateReset, "1372700873")
|
|
||||||
})
|
|
||||||
|
|
||||||
var expected int
|
|
||||||
|
|
||||||
if expected = 0; client.Rate.Limit != expected {
|
|
||||||
t.Errorf("Client rate limit = %v, expected %v", client.Rate.Limit, expected)
|
|
||||||
}
|
|
||||||
if expected = 0; client.Rate.Remaining != expected {
|
|
||||||
t.Errorf("Client rate remaining = %v, got %v", client.Rate.Remaining, expected)
|
|
||||||
}
|
|
||||||
if !client.Rate.Reset.IsZero() {
|
|
||||||
t.Errorf("Client rate reset not initialized to zero value")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, _ := client.NewRequest("GET", "/", nil)
|
|
||||||
client.Do(req, nil)
|
|
||||||
|
|
||||||
if expected = 60; client.Rate.Limit != expected {
|
|
||||||
t.Errorf("Client rate limit = %v, expected %v", client.Rate.Limit, expected)
|
|
||||||
}
|
|
||||||
if expected = 59; client.Rate.Remaining != expected {
|
|
||||||
t.Errorf("Client rate remaining = %v, expected %v", client.Rate.Remaining, expected)
|
|
||||||
}
|
|
||||||
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
|
|
||||||
if client.Rate.Reset.UTC() != reset {
|
|
||||||
t.Errorf("Client rate reset = %v, expected %v", client.Rate.Reset, reset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDo_rateLimit_errorResponse(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Add(headerRateLimit, "60")
|
|
||||||
w.Header().Add(headerRateRemaining, "59")
|
|
||||||
w.Header().Add(headerRateReset, "1372700873")
|
|
||||||
http.Error(w, "Bad Request", 400)
|
|
||||||
})
|
|
||||||
|
|
||||||
var expected int
|
|
||||||
|
|
||||||
req, _ := client.NewRequest("GET", "/", nil)
|
|
||||||
client.Do(req, nil)
|
|
||||||
|
|
||||||
if expected = 60; client.Rate.Limit != expected {
|
|
||||||
t.Errorf("Client rate limit = %v, expected %v", client.Rate.Limit, expected)
|
|
||||||
}
|
|
||||||
if expected = 59; client.Rate.Remaining != expected {
|
|
||||||
t.Errorf("Client rate remaining = %v, expected %v", client.Rate.Remaining, expected)
|
|
||||||
}
|
|
||||||
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
|
|
||||||
if client.Rate.Reset.UTC() != reset {
|
|
||||||
t.Errorf("Client rate reset = %v, expected %v", client.Rate.Reset, reset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
interfaceType := reflect.TypeOf(interfaceObject).Elem()
|
|
||||||
if !reflect.TypeOf(object).Implements(interfaceType) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCurrentPage(t *testing.T, resp *Response, expectedPage int) {
|
|
||||||
links := resp.Links
|
|
||||||
p, err := links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p != expectedPage {
|
|
||||||
t.Fatalf("expected current page to be '%d', was '%d'", expectedPage, p)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestImageActions_ImageActionsServiceOpImplementsImageActionsService(t *testing.T) {
|
|
||||||
if !Implements((*ImageActionsService)(nil), new(ImageActionsServiceOp)) {
|
|
||||||
t.Error("ImageActionsServiceOp does not implement ImageActionsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImageActions_Transfer(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
transferRequest := &ActionRequest{}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/images/12345/actions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(ActionRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, transferRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, transferRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
transfer, _, err := client.ImageActions.Transfer(12345, transferRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("ImageActions.Transfer returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(transfer, expected) {
|
|
||||||
t.Errorf("ImageActions.Transfer returned %+v, expected %+v", transfer, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImageActions_Get(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/images/123/actions/456", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
action, _, err := client.ImageActions.Get(123, 456)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("ImageActions.Get returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Action{Status: "in-progress"}
|
|
||||||
if !reflect.DeepEqual(action, expected) {
|
|
||||||
t.Errorf("ImageActions.Get returned %+v, expected %+v", action, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestImages_ImagesServiceOpImplementsImagesService(t *testing.T) {
|
|
||||||
if !Implements((*ImagesService)(nil), new(ImagesServiceOp)) {
|
|
||||||
t.Error("ImagesServiceOp does not implement ImagesService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImages_List(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/images", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"images":[{"id":1},{"id":2}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
images, _, err := client.Images.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Images.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Image{{ID: 1}, {ID: 2}}
|
|
||||||
if !reflect.DeepEqual(images, expected) {
|
|
||||||
t.Errorf("Images.List returned %+v, expected %+v", images, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImages_ListImagesMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/images", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"images": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/images/?page=2"}}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Images.List(&ListOptions{Page: 2})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImages_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"images": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/images/?page=3",
|
|
||||||
"prev":"http://example.com/v2/images/?page=1",
|
|
||||||
"last":"http://example.com/v2/images/?page=3",
|
|
||||||
"first":"http://example.com/v2/images/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/images", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Images.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImage_String(t *testing.T) {
|
|
||||||
image := &Image{
|
|
||||||
ID: 1,
|
|
||||||
Name: "Image",
|
|
||||||
Distribution: "Ubuntu",
|
|
||||||
Slug: "image",
|
|
||||||
Public: true,
|
|
||||||
Regions: []string{"one", "two"},
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := image.String()
|
|
||||||
expected := `godo.Image{ID:1, Name:"Image", Distribution:"Ubuntu", Slug:"image", Public:true, Regions:["one" "two"]}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Image.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestKeys_KeysServiceOpImplementsKeysService(t *testing.T) {
|
|
||||||
if !Implements((*KeysService)(nil), new(KeysServiceOp)) {
|
|
||||||
t.Error("KeysServiceOp does not implement KeysService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_List(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"ssh_keys":[{"id":1},{"id":2}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
keys, _, err := client.Keys.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Key{{ID: 1}, {ID: 2}}
|
|
||||||
if !reflect.DeepEqual(keys, expected) {
|
|
||||||
t.Errorf("Keys.List returned %+v, expected %+v", keys, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_ListKeysMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"droplets": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/account/keys/?page=2"}}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Keys.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"keys": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/account/keys/?page=3",
|
|
||||||
"prev":"http://example.com/v2/account/keys/?page=1",
|
|
||||||
"last":"http://example.com/v2/account/keys/?page=3",
|
|
||||||
"first":"http://example.com/v2/account/keys/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Keys.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_GetByID(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys/12345", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"ssh_key": {"id":12345}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
keys, _, err := client.Keys.GetByID(12345)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.GetByID returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Key{ID: 12345}
|
|
||||||
if !reflect.DeepEqual(keys, expected) {
|
|
||||||
t.Errorf("Keys.GetByID returned %+v, expected %+v", keys, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_GetByFingerprint(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys/aa:bb:cc", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"ssh_key": {"fingerprint":"aa:bb:cc"}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
keys, _, err := client.Keys.GetByFingerprint("aa:bb:cc")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.GetByFingerprint returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Key{Fingerprint: "aa:bb:cc"}
|
|
||||||
if !reflect.DeepEqual(keys, expected) {
|
|
||||||
t.Errorf("Keys.GetByFingerprint returned %+v, expected %+v", keys, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_Create(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
createRequest := &KeyCreateRequest{
|
|
||||||
Name: "name",
|
|
||||||
PublicKey: "ssh-rsa longtextandstuff",
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
v := new(KeyCreateRequest)
|
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
|
||||||
|
|
||||||
testMethod(t, r, "POST")
|
|
||||||
if !reflect.DeepEqual(v, createRequest) {
|
|
||||||
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `{"ssh_key":{"id":1}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
key, _, err := client.Keys.Create(createRequest)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.Create returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := &Key{ID: 1}
|
|
||||||
if !reflect.DeepEqual(key, expected) {
|
|
||||||
t.Errorf("Keys.Create returned %+v, expected %+v", key, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_DestroyByID(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys/12345", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "DELETE")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := client.Keys.DeleteByID(12345)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.Delete returned error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeys_DestroyByFingerprint(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/account/keys/aa:bb:cc", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "DELETE")
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := client.Keys.DeleteByFingerprint("aa:bb:cc")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Keys.Delete returned error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKey_String(t *testing.T) {
|
|
||||||
key := &Key{
|
|
||||||
ID: 123,
|
|
||||||
Name: "Key",
|
|
||||||
Fingerprint: "fingerprint",
|
|
||||||
PublicKey: "public key",
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := key.String()
|
|
||||||
expected := `godo.Key{ID:123, Name:"Key", Fingerprint:"fingerprint", PublicKey:"public key"}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Key.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
firstPageLinksJSONBlob = []byte(`{
|
|
||||||
"links": {
|
|
||||||
"pages": {
|
|
||||||
"last": "https://api.digitalocean.com/v2/droplets/?page=3",
|
|
||||||
"next": "https://api.digitalocean.com/v2/droplets/?page=2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
otherPageLinksJSONBlob = []byte(`{
|
|
||||||
"links": {
|
|
||||||
"pages": {
|
|
||||||
"first": "https://api.digitalocean.com/v2/droplets/?page=1",
|
|
||||||
"prev": "https://api.digitalocean.com/v2/droplets/?page=1",
|
|
||||||
"last": "https://api.digitalocean.com/v2/droplets/?page=3",
|
|
||||||
"next": "https://api.digitalocean.com/v2/droplets/?page=3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
lastPageLinksJSONBlob = []byte(`{
|
|
||||||
"links": {
|
|
||||||
"pages": {
|
|
||||||
"first": "https://api.digitalocean.com/v2/droplets/?page=1",
|
|
||||||
"prev": "https://api.digitalocean.com/v2/droplets/?page=2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
missingLinksJSONBlob = []byte(`{ }`)
|
|
||||||
)
|
|
||||||
|
|
||||||
type godoList struct {
|
|
||||||
Links Links `json:"links"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadLinksJSON(t *testing.T, j []byte) Links {
|
|
||||||
var list godoList
|
|
||||||
err := json.Unmarshal(j, &list)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.Links
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseFirst(t *testing.T) {
|
|
||||||
links := loadLinksJSON(t, firstPageLinksJSONBlob)
|
|
||||||
_, err := links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Response{Links: &links}
|
|
||||||
checkCurrentPage(t, r, 1)
|
|
||||||
|
|
||||||
if links.IsLastPage() {
|
|
||||||
t.Fatalf("shouldn't be last page")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseMiddle(t *testing.T) {
|
|
||||||
links := loadLinksJSON(t, otherPageLinksJSONBlob)
|
|
||||||
_, err := links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Response{Links: &links}
|
|
||||||
checkCurrentPage(t, r, 2)
|
|
||||||
|
|
||||||
if links.IsLastPage() {
|
|
||||||
t.Fatalf("shouldn't be last page")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseLast(t *testing.T) {
|
|
||||||
links := loadLinksJSON(t, lastPageLinksJSONBlob)
|
|
||||||
_, err := links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Response{Links: &links}
|
|
||||||
checkCurrentPage(t, r, 3)
|
|
||||||
if !links.IsLastPage() {
|
|
||||||
t.Fatalf("expected last page")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseMissing(t *testing.T) {
|
|
||||||
links := loadLinksJSON(t, missingLinksJSONBlob)
|
|
||||||
_, err := links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Response{Links: &links}
|
|
||||||
checkCurrentPage(t, r, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseURL(t *testing.T) {
|
|
||||||
type linkTest struct {
|
|
||||||
name, url string
|
|
||||||
expected int
|
|
||||||
}
|
|
||||||
|
|
||||||
linkTests := []linkTest{
|
|
||||||
{
|
|
||||||
name: "prev",
|
|
||||||
url: "https://api.digitalocean.com/v2/droplets/?page=1",
|
|
||||||
expected: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "last",
|
|
||||||
url: "https://api.digitalocean.com/v2/droplets/?page=5",
|
|
||||||
expected: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "nexta",
|
|
||||||
url: "https://api.digitalocean.com/v2/droplets/?page=2",
|
|
||||||
expected: 2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, lT := range linkTests {
|
|
||||||
p, err := pageForURL(lT.url)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p != lT.expected {
|
|
||||||
t.Error("expected page for '%s' to be '%d', was '%d'",
|
|
||||||
lT.url, lT.expected, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinks_ParseEmptyString(t *testing.T) {
|
|
||||||
type linkTest struct {
|
|
||||||
name, url string
|
|
||||||
expected int
|
|
||||||
}
|
|
||||||
|
|
||||||
linkTests := []linkTest{
|
|
||||||
{
|
|
||||||
name: "none",
|
|
||||||
url: "http://example.com",
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bad",
|
|
||||||
url: "no url",
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
url: "",
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, lT := range linkTests {
|
|
||||||
_, err := pageForURL(lT.url)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected error for test '%s', but received none", lT.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRegions_RegionsServiceOpImplementsRegionsService(t *testing.T) {
|
|
||||||
if !Implements((*RegionsService)(nil), new(RegionsServiceOp)) {
|
|
||||||
t.Error("RegionsServiceOp does not implement RegionsService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegions_List(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/regions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"regions":[{"slug":"1"},{"slug":"2"}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
regions, _, err := client.Regions.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Regions.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Region{{Slug: "1"}, {Slug: "2"}}
|
|
||||||
if !reflect.DeepEqual(regions, expected) {
|
|
||||||
t.Errorf("Regions.List returned %+v, expected %+v", regions, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegions_ListRegionsMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/regions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"regions": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/regions/?page=2"}}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Regions.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegions_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"regions": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/regions/?page=3",
|
|
||||||
"prev":"http://example.com/v2/regions/?page=1",
|
|
||||||
"last":"http://example.com/v2/regions/?page=3",
|
|
||||||
"first":"http://example.com/v2/regions/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/regions", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Regions.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegion_String(t *testing.T) {
|
|
||||||
region := &Region{
|
|
||||||
Slug: "region",
|
|
||||||
Name: "Region",
|
|
||||||
Sizes: []string{"1", "2"},
|
|
||||||
Available: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := region.String()
|
|
||||||
expected := `godo.Region{Slug:"region", Name:"Region", Sizes:["1" "2"], Available:true}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Region.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSizes_SizesServiceOpImplementsSizesService(t *testing.T) {
|
|
||||||
if !Implements((*SizesService)(nil), new(SizesServiceOp)) {
|
|
||||||
t.Error("SizesServiceOp does not implement SizesService")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSizes_List(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/sizes", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"sizes":[{"slug":"1"},{"slug":"2"}]}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
sizes, _, err := client.Sizes.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Sizes.List returned error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := []Size{{Slug: "1"}, {Slug: "2"}}
|
|
||||||
if !reflect.DeepEqual(sizes, expected) {
|
|
||||||
t.Errorf("Sizes.List returned %+v, expected %+v", sizes, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSizes_ListSizesMultiplePages(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/sizes", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, `{"sizes": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/sizes/?page=2"}}}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
_, resp, err := client.Sizes.List(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSizes_RetrievePageByNumber(t *testing.T) {
|
|
||||||
setup()
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
jBlob := `
|
|
||||||
{
|
|
||||||
"sizes": [{"id":1},{"id":2}],
|
|
||||||
"links":{
|
|
||||||
"pages":{
|
|
||||||
"next":"http://example.com/v2/sizes/?page=3",
|
|
||||||
"prev":"http://example.com/v2/sizes/?page=1",
|
|
||||||
"last":"http://example.com/v2/sizes/?page=3",
|
|
||||||
"first":"http://example.com/v2/sizes/?page=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
mux.HandleFunc("/v2/sizes", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
testMethod(t, r, "GET")
|
|
||||||
fmt.Fprint(w, jBlob)
|
|
||||||
})
|
|
||||||
|
|
||||||
opt := &ListOptions{Page: 2}
|
|
||||||
_, resp, err := client.Sizes.List(opt)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentPage(t, resp, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSize_String(t *testing.T) {
|
|
||||||
size := &Size{
|
|
||||||
Slug: "slize",
|
|
||||||
Memory: 123,
|
|
||||||
Vcpus: 456,
|
|
||||||
Disk: 789,
|
|
||||||
PriceMonthly: 123,
|
|
||||||
PriceHourly: 456,
|
|
||||||
Regions: []string{"1", "2"},
|
|
||||||
}
|
|
||||||
|
|
||||||
stringified := size.String()
|
|
||||||
expected := `godo.Size{Slug:"slize", Memory:123, Vcpus:456, Disk:789, PriceMonthly:123, PriceHourly:456, Regions:["1" "2"]}`
|
|
||||||
if expected != stringified {
|
|
||||||
t.Errorf("Size.String returned %+v, expected %+v", stringified, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
emptyTimeStr = `"0001-01-01T00:00:00Z"`
|
|
||||||
referenceTimeStr = `"2006-01-02T15:04:05Z"`
|
|
||||||
referenceUnixTimeStr = `1136214245`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
referenceTime = time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)
|
|
||||||
unixOrigin = time.Unix(0, 0).In(time.UTC)
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTimestamp_Marshal(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data Timestamp
|
|
||||||
want string
|
|
||||||
wantErr bool
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{"Reference", Timestamp{referenceTime}, referenceTimeStr, false, true},
|
|
||||||
{"Empty", Timestamp{}, emptyTimeStr, false, true},
|
|
||||||
{"Mismatch", Timestamp{}, referenceTimeStr, false, false},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
out, err := json.Marshal(tc.data)
|
|
||||||
if gotErr := (err != nil); gotErr != tc.wantErr {
|
|
||||||
t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
|
|
||||||
}
|
|
||||||
got := string(out)
|
|
||||||
equal := got == tc.want
|
|
||||||
if (got == tc.want) != tc.equal {
|
|
||||||
t.Errorf("%s: got=%s, want=%s, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTimestamp_Unmarshal(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data string
|
|
||||||
want Timestamp
|
|
||||||
wantErr bool
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{"Reference", referenceTimeStr, Timestamp{referenceTime}, false, true},
|
|
||||||
{"ReferenceUnix", `1136214245`, Timestamp{referenceTime}, false, true},
|
|
||||||
{"Empty", emptyTimeStr, Timestamp{}, false, true},
|
|
||||||
{"UnixStart", `0`, Timestamp{unixOrigin}, false, true},
|
|
||||||
{"Mismatch", referenceTimeStr, Timestamp{}, false, false},
|
|
||||||
{"MismatchUnix", `0`, Timestamp{}, false, false},
|
|
||||||
{"Invalid", `"asdf"`, Timestamp{referenceTime}, true, false},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
var got Timestamp
|
|
||||||
err := json.Unmarshal([]byte(tc.data), &got)
|
|
||||||
if gotErr := err != nil; gotErr != tc.wantErr {
|
|
||||||
t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
equal := got.Equal(tc.want)
|
|
||||||
if equal != tc.equal {
|
|
||||||
t.Errorf("%s: got=%#v, want=%#v, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTimstamp_MarshalReflexivity(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data Timestamp
|
|
||||||
}{
|
|
||||||
{"Reference", Timestamp{referenceTime}},
|
|
||||||
{"Empty", Timestamp{}},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
data, err := json.Marshal(tc.data)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%s: Marshal err=%v", tc.desc, err)
|
|
||||||
}
|
|
||||||
var got Timestamp
|
|
||||||
err = json.Unmarshal(data, &got)
|
|
||||||
if !got.Equal(tc.data) {
|
|
||||||
t.Errorf("%s: %+v != %+v", tc.desc, got, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrappedTimestamp struct {
|
|
||||||
A int
|
|
||||||
Time Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrappedTimstamp_Marshal(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data WrappedTimestamp
|
|
||||||
want string
|
|
||||||
wantErr bool
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{"Reference", WrappedTimestamp{0, Timestamp{referenceTime}}, fmt.Sprintf(`{"A":0,"Time":%s}`, referenceTimeStr), false, true},
|
|
||||||
{"Empty", WrappedTimestamp{}, fmt.Sprintf(`{"A":0,"Time":%s}`, emptyTimeStr), false, true},
|
|
||||||
{"Mismatch", WrappedTimestamp{}, fmt.Sprintf(`{"A":0,"Time":%s}`, referenceTimeStr), false, false},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
out, err := json.Marshal(tc.data)
|
|
||||||
if gotErr := err != nil; gotErr != tc.wantErr {
|
|
||||||
t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
|
|
||||||
}
|
|
||||||
got := string(out)
|
|
||||||
equal := got == tc.want
|
|
||||||
if equal != tc.equal {
|
|
||||||
t.Errorf("%s: got=%s, want=%s, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrappedTimestamp_Unmarshal(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data string
|
|
||||||
want WrappedTimestamp
|
|
||||||
wantErr bool
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{"Reference", referenceTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true},
|
|
||||||
{"ReferenceUnix", referenceUnixTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true},
|
|
||||||
{"Empty", emptyTimeStr, WrappedTimestamp{0, Timestamp{}}, false, true},
|
|
||||||
{"UnixStart", `0`, WrappedTimestamp{0, Timestamp{unixOrigin}}, false, true},
|
|
||||||
{"Mismatch", referenceTimeStr, WrappedTimestamp{0, Timestamp{}}, false, false},
|
|
||||||
{"MismatchUnix", `0`, WrappedTimestamp{0, Timestamp{}}, false, false},
|
|
||||||
{"Invalid", `"asdf"`, WrappedTimestamp{0, Timestamp{referenceTime}}, true, false},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
var got Timestamp
|
|
||||||
err := json.Unmarshal([]byte(tc.data), &got)
|
|
||||||
if gotErr := err != nil; gotErr != tc.wantErr {
|
|
||||||
t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
equal := got.Time.Equal(tc.want.Time.Time)
|
|
||||||
if equal != tc.equal {
|
|
||||||
t.Errorf("%s: got=%#v, want=%#v, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrappedTimestamp_MarshalReflexivity(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
desc string
|
|
||||||
data WrappedTimestamp
|
|
||||||
}{
|
|
||||||
{"Reference", WrappedTimestamp{0, Timestamp{referenceTime}}},
|
|
||||||
{"Empty", WrappedTimestamp{0, Timestamp{}}},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
bytes, err := json.Marshal(tc.data)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%s: Marshal err=%v", tc.desc, err)
|
|
||||||
}
|
|
||||||
var got WrappedTimestamp
|
|
||||||
err = json.Unmarshal(bytes, &got)
|
|
||||||
if !got.Time.Equal(tc.data.Time) {
|
|
||||||
t.Errorf("%s: %+v != %+v", tc.desc, got, tc.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2013-2015 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,19 @@
|
||||||
|
Docker
|
||||||
|
Copyright 2012-2014 Docker, Inc.
|
||||||
|
|
||||||
|
This product includes software developed at Docker, Inc. (http://www.docker.com).
|
||||||
|
|
||||||
|
This product contains software (https://github.com/kr/pty) developed
|
||||||
|
by Keith Rarick, licensed under the MIT License.
|
||||||
|
|
||||||
|
The following is courtesy of our legal counsel:
|
||||||
|
|
||||||
|
|
||||||
|
Use and transfer of Docker may be subject to certain restrictions by the
|
||||||
|
United States and other governments.
|
||||||
|
It is your responsibility to ensure that your use and/or transfer does not
|
||||||
|
violate applicable laws.
|
||||||
|
|
||||||
|
For more information, please see http://www.bis.doc.gov
|
||||||
|
|
||||||
|
See also http://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2013 Honza Pokorny
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2014-2015 The Docker & Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2014-2015 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2014-2015 The Docker & Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
vendor/github.com/docker/docker/vendor/src/code.google.com/p/go.net/LICENSE
generated
vendored
Normal file
27
vendor/github.com/docker/docker/vendor/src/code.google.com/p/go.net/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/github.com/docker/docker/vendor/src/code.google.com/p/go.net/PATENTS
generated
vendored
Normal file
22
vendor/github.com/docker/docker/vendor/src/code.google.com/p/go.net/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google 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,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
21
vendor/github.com/docker/docker/vendor/src/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
vendor/github.com/docker/docker/vendor/src/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
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.
|
191
vendor/github.com/docker/docker/vendor/src/github.com/coreos/go-systemd/LICENSE
generated
vendored
Normal file
191
vendor/github.com/docker/docker/vendor/src/github.com/coreos/go-systemd/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
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:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
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
|
||||||
|
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.
|
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/LICENSE
generated
vendored
Normal file
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2014 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
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.
|
16
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/NOTICE
generated
vendored
Normal file
16
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/NOTICE
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
libcontainer
|
||||||
|
Copyright 2012-2014 Docker, Inc.
|
||||||
|
|
||||||
|
This product includes software developed at Docker, Inc. (http://www.docker.com).
|
||||||
|
|
||||||
|
The following is courtesy of our legal counsel:
|
||||||
|
|
||||||
|
|
||||||
|
Use and transfer of Docker may be subject to certain restrictions by the
|
||||||
|
United States and other governments.
|
||||||
|
It is your responsibility to ensure that your use and/or transfer does not
|
||||||
|
violate applicable laws.
|
||||||
|
|
||||||
|
For more information, please see http://www.bis.doc.gov
|
||||||
|
|
||||||
|
See also http://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libtrust/LICENSE
generated
vendored
Normal file
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libtrust/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2014 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
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.
|
28
vendor/github.com/docker/docker/vendor/src/github.com/go-fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
28
vendor/github.com/docker/docker/vendor/src/github.com/go-fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
vendor/github.com/docker/docker/vendor/src/github.com/godbus/dbus/LICENSE
generated
vendored
Normal file
25
vendor/github.com/docker/docker/vendor/src/github.com/godbus/dbus/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
vendor/github.com/docker/docker/vendor/src/github.com/gorilla/context/LICENSE
generated
vendored
Normal file
27
vendor/github.com/docker/docker/vendor/src/github.com/gorilla/context/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
vendor/github.com/docker/docker/vendor/src/github.com/gorilla/mux/LICENSE
generated
vendored
Normal file
27
vendor/github.com/docker/docker/vendor/src/github.com/gorilla/mux/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
vendor/github.com/docker/docker/vendor/src/github.com/kr/pty/License
generated
vendored
Normal file
23
vendor/github.com/docker/docker/vendor/src/github.com/kr/pty/License
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (c) 2011 Keith Rarick
|
||||||
|
|
||||||
|
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.
|
24
vendor/github.com/docker/docker/vendor/src/github.com/syndtr/gocapability/LICENSE
generated
vendored
Normal file
24
vendor/github.com/docker/docker/vendor/src/github.com/syndtr/gocapability/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
20
vendor/github.com/docker/docker/vendor/src/github.com/tchap/go-patricia/LICENSE
generated
vendored
Normal file
20
vendor/github.com/docker/docker/vendor/src/github.com/tchap/go-patricia/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 The AUTHORS
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013 Google. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,238 +0,0 @@
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package query
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestValues_types(t *testing.T) {
|
|
||||||
str := "string"
|
|
||||||
strPtr := &str
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
in interface{}
|
|
||||||
want url.Values
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
// basic primitives
|
|
||||||
struct {
|
|
||||||
A string
|
|
||||||
B int
|
|
||||||
C uint
|
|
||||||
D float32
|
|
||||||
E bool
|
|
||||||
}{},
|
|
||||||
url.Values{
|
|
||||||
"A": {""},
|
|
||||||
"B": {"0"},
|
|
||||||
"C": {"0"},
|
|
||||||
"D": {"0"},
|
|
||||||
"E": {"false"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// pointers
|
|
||||||
struct {
|
|
||||||
A *string
|
|
||||||
B *int
|
|
||||||
C **string
|
|
||||||
}{A: strPtr, C: &strPtr},
|
|
||||||
url.Values{
|
|
||||||
"A": {str},
|
|
||||||
"B": {""},
|
|
||||||
"C": {str},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// slices and arrays
|
|
||||||
struct {
|
|
||||||
A []string
|
|
||||||
B []string `url:",comma"`
|
|
||||||
C []string `url:",space"`
|
|
||||||
D [2]string
|
|
||||||
E [2]string `url:",comma"`
|
|
||||||
F [2]string `url:",space"`
|
|
||||||
G []*string `url:",space"`
|
|
||||||
H []bool `url:",int,space"`
|
|
||||||
}{
|
|
||||||
A: []string{"a", "b"},
|
|
||||||
B: []string{"a", "b"},
|
|
||||||
C: []string{"a", "b"},
|
|
||||||
D: [2]string{"a", "b"},
|
|
||||||
E: [2]string{"a", "b"},
|
|
||||||
F: [2]string{"a", "b"},
|
|
||||||
G: []*string{&str, &str},
|
|
||||||
H: []bool{true, false},
|
|
||||||
},
|
|
||||||
url.Values{
|
|
||||||
"A": {"a", "b"},
|
|
||||||
"B": {"a,b"},
|
|
||||||
"C": {"a b"},
|
|
||||||
"D": {"a", "b"},
|
|
||||||
"E": {"a,b"},
|
|
||||||
"F": {"a b"},
|
|
||||||
"G": {"string string"},
|
|
||||||
"H": {"1 0"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// other types
|
|
||||||
struct {
|
|
||||||
A time.Time
|
|
||||||
B time.Time `url:",unix"`
|
|
||||||
C bool `url:",int"`
|
|
||||||
D bool `url:",int"`
|
|
||||||
}{
|
|
||||||
A: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
|
|
||||||
B: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
|
|
||||||
C: true,
|
|
||||||
D: false,
|
|
||||||
},
|
|
||||||
url.Values{
|
|
||||||
"A": {"2000-01-01T12:34:56Z"},
|
|
||||||
"B": {"946730096"},
|
|
||||||
"C": {"1"},
|
|
||||||
"D": {"0"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
v, err := Values(tt.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tt.want, v) {
|
|
||||||
t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValues_omitEmpty(t *testing.T) {
|
|
||||||
str := ""
|
|
||||||
s := struct {
|
|
||||||
a string
|
|
||||||
A string
|
|
||||||
B string `url:",omitempty"`
|
|
||||||
C string `url:"-"`
|
|
||||||
D string `url:"omitempty"` // actually named omitempty, not an option
|
|
||||||
E *string `url:",omitempty"`
|
|
||||||
}{E: &str}
|
|
||||||
|
|
||||||
v, err := Values(s)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Values(%q) returned error: %v", s, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
want := url.Values{
|
|
||||||
"A": {""},
|
|
||||||
"omitempty": {""},
|
|
||||||
"E": {""}, // E is included because the pointer is not empty, even though the string being pointed to is
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(want, v) {
|
|
||||||
t.Errorf("Values(%q) returned %v, want %v", s, v, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type A struct {
|
|
||||||
B
|
|
||||||
}
|
|
||||||
|
|
||||||
type B struct {
|
|
||||||
C string
|
|
||||||
}
|
|
||||||
|
|
||||||
type D struct {
|
|
||||||
B
|
|
||||||
C string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValues_embeddedStructs(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
in interface{}
|
|
||||||
want url.Values
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
A{B{C: "foo"}},
|
|
||||||
url.Values{"C": {"foo"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
D{B: B{C: "bar"}, C: "foo"},
|
|
||||||
url.Values{"C": {"foo", "bar"}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
v, err := Values(tt.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tt.want, v) {
|
|
||||||
t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValues_invalidInput(t *testing.T) {
|
|
||||||
_, err := Values("")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected Values() to return an error on invalid input")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type EncodedArgs []string
|
|
||||||
|
|
||||||
func (m EncodedArgs) EncodeValues(v *url.Values) error {
|
|
||||||
for i, arg := range m {
|
|
||||||
v.Set(fmt.Sprintf("arg.%d", i), arg)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValues_Marshaler(t *testing.T) {
|
|
||||||
s := struct {
|
|
||||||
Args EncodedArgs `url:"args"`
|
|
||||||
}{[]string{"a", "b", "c"}}
|
|
||||||
v, err := Values(s)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Values(%q) returned error: %v", s, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
want := url.Values{
|
|
||||||
"arg.0": {"a"},
|
|
||||||
"arg.1": {"b"},
|
|
||||||
"arg.2": {"c"},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(want, v) {
|
|
||||||
t.Errorf("Values(%q) returned %v, want %v", s, v, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTagParsing(t *testing.T) {
|
|
||||||
name, opts := parseTag("field,foobar,foo")
|
|
||||||
if name != "field" {
|
|
||||||
t.Fatalf("name = %q, want field", name)
|
|
||||||
}
|
|
||||||
for _, tt := range []struct {
|
|
||||||
opt string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{"foobar", true},
|
|
||||||
{"foo", true},
|
|
||||||
{"bar", false},
|
|
||||||
{"field", false},
|
|
||||||
} {
|
|
||||||
if opts.Contains(tt.opt) != tt.want {
|
|
||||||
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
package mapstructure
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestComposeDecodeHookFunc(t *testing.T) {
|
|
||||||
f1 := func(
|
|
||||||
f reflect.Kind,
|
|
||||||
t reflect.Kind,
|
|
||||||
data interface{}) (interface{}, error) {
|
|
||||||
return data.(string) + "foo", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f2 := func(
|
|
||||||
f reflect.Kind,
|
|
||||||
t reflect.Kind,
|
|
||||||
data interface{}) (interface{}, error) {
|
|
||||||
return data.(string) + "bar", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f := ComposeDecodeHookFunc(f1, f2)
|
|
||||||
|
|
||||||
result, err := f(reflect.String, reflect.Slice, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
if result.(string) != "foobar" {
|
|
||||||
t.Fatalf("bad: %#v", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestComposeDecodeHookFunc_err(t *testing.T) {
|
|
||||||
f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
|
|
||||||
return nil, errors.New("foo")
|
|
||||||
}
|
|
||||||
|
|
||||||
f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
|
|
||||||
panic("NOPE")
|
|
||||||
}
|
|
||||||
|
|
||||||
f := ComposeDecodeHookFunc(f1, f2)
|
|
||||||
|
|
||||||
_, err := f(reflect.String, reflect.Slice, 42)
|
|
||||||
if err.Error() != "foo" {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestComposeDecodeHookFunc_kinds(t *testing.T) {
|
|
||||||
var f2From reflect.Kind
|
|
||||||
|
|
||||||
f1 := func(
|
|
||||||
f reflect.Kind,
|
|
||||||
t reflect.Kind,
|
|
||||||
data interface{}) (interface{}, error) {
|
|
||||||
return int(42), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f2 := func(
|
|
||||||
f reflect.Kind,
|
|
||||||
t reflect.Kind,
|
|
||||||
data interface{}) (interface{}, error) {
|
|
||||||
f2From = f
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f := ComposeDecodeHookFunc(f1, f2)
|
|
||||||
|
|
||||||
_, err := f(reflect.String, reflect.Slice, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
if f2From != reflect.Int {
|
|
||||||
t.Fatalf("bad: %#v", f2From)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStringToSliceHookFunc(t *testing.T) {
|
|
||||||
f := StringToSliceHookFunc(",")
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
f, t reflect.Kind
|
|
||||||
data interface{}
|
|
||||||
result interface{}
|
|
||||||
err bool
|
|
||||||
}{
|
|
||||||
{reflect.Slice, reflect.Slice, 42, 42, false},
|
|
||||||
{reflect.String, reflect.String, 42, 42, false},
|
|
||||||
{
|
|
||||||
reflect.String,
|
|
||||||
reflect.Slice,
|
|
||||||
"foo,bar,baz",
|
|
||||||
[]string{"foo", "bar", "baz"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
reflect.String,
|
|
||||||
reflect.Slice,
|
|
||||||
"",
|
|
||||||
[]string{},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
actual, err := f(tc.f, tc.t, tc.data)
|
|
||||||
if tc.err != (err != nil) {
|
|
||||||
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(actual, tc.result) {
|
|
||||||
t.Fatalf(
|
|
||||||
"case %d: expected %#v, got %#v",
|
|
||||||
i, tc.result, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWeaklyTypedHook(t *testing.T) {
|
|
||||||
var f DecodeHookFunc = WeaklyTypedHook
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
f, t reflect.Kind
|
|
||||||
data interface{}
|
|
||||||
result interface{}
|
|
||||||
err bool
|
|
||||||
}{
|
|
||||||
// TO STRING
|
|
||||||
{
|
|
||||||
reflect.Bool,
|
|
||||||
reflect.String,
|
|
||||||
false,
|
|
||||||
"0",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
reflect.Bool,
|
|
||||||
reflect.String,
|
|
||||||
true,
|
|
||||||
"1",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
reflect.Float32,
|
|
||||||
reflect.String,
|
|
||||||
float32(7),
|
|
||||||
"7",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
reflect.Int,
|
|
||||||
reflect.String,
|
|
||||||
int(7),
|
|
||||||
"7",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
reflect.Slice,
|
|
||||||
reflect.String,
|
|
||||||
[]uint8("foo"),
|
|
||||||
"foo",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
reflect.Uint,
|
|
||||||
reflect.String,
|
|
||||||
uint(7),
|
|
||||||
"7",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
actual, err := f(tc.f, tc.t, tc.data)
|
|
||||||
if tc.err != (err != nil) {
|
|
||||||
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(actual, tc.result) {
|
|
||||||
t.Fatalf(
|
|
||||||
"case %d: expected %#v, got %#v",
|
|
||||||
i, tc.result, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
package mapstructure
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Benchmark_Decode(b *testing.B) {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
Emails []string
|
|
||||||
Extra map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": "Mitchell",
|
|
||||||
"age": 91,
|
|
||||||
"emails": []string{"one", "two", "three"},
|
|
||||||
"extra": map[string]string{
|
|
||||||
"twitter": "mitchellh",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeBasic(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vint": 42,
|
|
||||||
"Vuint": 42,
|
|
||||||
"vbool": true,
|
|
||||||
"Vfloat": 42.42,
|
|
||||||
"vsilent": true,
|
|
||||||
"vdata": 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeEmbedded(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"Basic": map[string]interface{}{
|
|
||||||
"vstring": "innerfoo",
|
|
||||||
},
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Embedded
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeTypeConversion(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"IntToFloat": 42,
|
|
||||||
"IntToUint": 42,
|
|
||||||
"IntToBool": 1,
|
|
||||||
"IntToString": 42,
|
|
||||||
"UintToInt": 42,
|
|
||||||
"UintToFloat": 42,
|
|
||||||
"UintToBool": 42,
|
|
||||||
"UintToString": 42,
|
|
||||||
"BoolToInt": true,
|
|
||||||
"BoolToUint": true,
|
|
||||||
"BoolToFloat": true,
|
|
||||||
"BoolToString": true,
|
|
||||||
"FloatToInt": 42.42,
|
|
||||||
"FloatToUint": 42.42,
|
|
||||||
"FloatToBool": 42.42,
|
|
||||||
"FloatToString": 42.42,
|
|
||||||
"StringToInt": "42",
|
|
||||||
"StringToUint": "42",
|
|
||||||
"StringToBool": "1",
|
|
||||||
"StringToFloat": "42.42",
|
|
||||||
"SliceToMap": []interface{}{},
|
|
||||||
"MapToSlice": map[string]interface{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultStrict TypeConversionResult
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &resultStrict)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeMap(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vother": map[interface{}]interface{}{
|
|
||||||
"foo": "foo",
|
|
||||||
"bar": "bar",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Map
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeMapOfStruct(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"value": map[string]interface{}{
|
|
||||||
"foo": map[string]string{"vstring": "one"},
|
|
||||||
"bar": map[string]string{"vstring": "two"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result MapOfStruct
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeSlice(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": []string{"foo", "bar", "baz"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Slice
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeSliceOfStruct(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"value": []map[string]interface{}{
|
|
||||||
{"vstring": "one"},
|
|
||||||
{"vstring": "two"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result SliceOfStruct
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeWeaklyTypedInput(b *testing.B) {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
Emails []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// This input can come from anywhere, but typically comes from
|
|
||||||
// something like decoding JSON, generated by a weakly typed language
|
|
||||||
// such as PHP.
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": 123, // number => string
|
|
||||||
"age": "42", // string => number
|
|
||||||
"emails": map[string]interface{}{}, // empty map => empty array
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
config := &DecoderConfig{
|
|
||||||
WeaklyTypedInput: true,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
decoder.Decode(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeMetadata(b *testing.B) {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
}
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": "Mitchell",
|
|
||||||
"age": 91,
|
|
||||||
"email": "foo@bar.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
var md Metadata
|
|
||||||
var result Person
|
|
||||||
config := &DecoderConfig{
|
|
||||||
Metadata: &md,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
decoder.Decode(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeMetadataEmbedded(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var md Metadata
|
|
||||||
var result EmbeddedSquash
|
|
||||||
config := &DecoderConfig{
|
|
||||||
Metadata: &md,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
decoder.Decode(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_DecodeTagged(b *testing.B) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
"bar": "value",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Tagged
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Decode(input, &result)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package mapstructure
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
// GH-1
|
|
||||||
func TestDecode_NilValue(t *testing.T) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": nil,
|
|
||||||
"vother": nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Map
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != "" {
|
|
||||||
t.Fatalf("value should be default: %s", result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vother != nil {
|
|
||||||
t.Fatalf("Vother should be nil: %s", result.Vother)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GH-10
|
|
||||||
func TestDecode_mapInterfaceInterface(t *testing.T) {
|
|
||||||
input := map[interface{}]interface{}{
|
|
||||||
"vfoo": nil,
|
|
||||||
"vother": nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Map
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != "" {
|
|
||||||
t.Fatalf("value should be default: %s", result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vother != nil {
|
|
||||||
t.Fatalf("Vother should be nil: %s", result.Vother)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
package mapstructure
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleDecode() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
Emails []string
|
|
||||||
Extra map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// This input can come from anywhere, but typically comes from
|
|
||||||
// something like decoding JSON where we're not quite sure of the
|
|
||||||
// struct initially.
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": "Mitchell",
|
|
||||||
"age": 91,
|
|
||||||
"emails": []string{"one", "two", "three"},
|
|
||||||
"extra": map[string]string{
|
|
||||||
"twitter": "mitchellh",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%#v", result)
|
|
||||||
// Output:
|
|
||||||
// mapstructure.Person{Name:"Mitchell", Age:91, Emails:[]string{"one", "two", "three"}, Extra:map[string]string{"twitter":"mitchellh"}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleDecode_errors() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
Emails []string
|
|
||||||
Extra map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// This input can come from anywhere, but typically comes from
|
|
||||||
// something like decoding JSON where we're not quite sure of the
|
|
||||||
// struct initially.
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": 123,
|
|
||||||
"age": "bad value",
|
|
||||||
"emails": []int{1, 2, 3},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err == nil {
|
|
||||||
panic("should have an error")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
// Output:
|
|
||||||
// 5 error(s) decoding:
|
|
||||||
//
|
|
||||||
// * 'Name' expected type 'string', got unconvertible type 'int'
|
|
||||||
// * 'Age' expected type 'int', got unconvertible type 'string'
|
|
||||||
// * 'Emails[0]' expected type 'string', got unconvertible type 'int'
|
|
||||||
// * 'Emails[1]' expected type 'string', got unconvertible type 'int'
|
|
||||||
// * 'Emails[2]' expected type 'string', got unconvertible type 'int'
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleDecode_metadata() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
}
|
|
||||||
|
|
||||||
// This input can come from anywhere, but typically comes from
|
|
||||||
// something like decoding JSON where we're not quite sure of the
|
|
||||||
// struct initially.
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": "Mitchell",
|
|
||||||
"age": 91,
|
|
||||||
"email": "foo@bar.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
// For metadata, we make a more advanced DecoderConfig so we can
|
|
||||||
// more finely configure the decoder that is used. In this case, we
|
|
||||||
// just tell the decoder we want to track metadata.
|
|
||||||
var md Metadata
|
|
||||||
var result Person
|
|
||||||
config := &DecoderConfig{
|
|
||||||
Metadata: &md,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := decoder.Decode(input); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Unused keys: %#v", md.Unused)
|
|
||||||
// Output:
|
|
||||||
// Unused keys: []string{"email"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleDecode_weaklyTypedInput() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
Emails []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// This input can come from anywhere, but typically comes from
|
|
||||||
// something like decoding JSON, generated by a weakly typed language
|
|
||||||
// such as PHP.
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"name": 123, // number => string
|
|
||||||
"age": "42", // string => number
|
|
||||||
"emails": map[string]interface{}{}, // empty map => empty array
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
config := &DecoderConfig{
|
|
||||||
WeaklyTypedInput: true,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%#v", result)
|
|
||||||
// Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleDecode_tags() {
|
|
||||||
// Note that the mapstructure tags defined in the struct type
|
|
||||||
// can indicate which fields the values are mapped to.
|
|
||||||
type Person struct {
|
|
||||||
Name string `mapstructure:"person_name"`
|
|
||||||
Age int `mapstructure:"person_age"`
|
|
||||||
}
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"person_name": "Mitchell",
|
|
||||||
"person_age": 91,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Person
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%#v", result)
|
|
||||||
// Output:
|
|
||||||
// mapstructure.Person{Name:"Mitchell", Age:91}
|
|
||||||
}
|
|
|
@ -1,828 +0,0 @@
|
||||||
package mapstructure
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Basic struct {
|
|
||||||
Vstring string
|
|
||||||
Vint int
|
|
||||||
Vuint uint
|
|
||||||
Vbool bool
|
|
||||||
Vfloat float64
|
|
||||||
Vextra string
|
|
||||||
vsilent bool
|
|
||||||
Vdata interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Embedded struct {
|
|
||||||
Basic
|
|
||||||
Vunique string
|
|
||||||
}
|
|
||||||
|
|
||||||
type EmbeddedPointer struct {
|
|
||||||
*Basic
|
|
||||||
Vunique string
|
|
||||||
}
|
|
||||||
|
|
||||||
type EmbeddedSquash struct {
|
|
||||||
Basic `mapstructure:",squash"`
|
|
||||||
Vunique string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Map struct {
|
|
||||||
Vfoo string
|
|
||||||
Vother map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MapOfStruct struct {
|
|
||||||
Value map[string]Basic
|
|
||||||
}
|
|
||||||
|
|
||||||
type Nested struct {
|
|
||||||
Vfoo string
|
|
||||||
Vbar Basic
|
|
||||||
}
|
|
||||||
|
|
||||||
type NestedPointer struct {
|
|
||||||
Vfoo string
|
|
||||||
Vbar *Basic
|
|
||||||
}
|
|
||||||
|
|
||||||
type Slice struct {
|
|
||||||
Vfoo string
|
|
||||||
Vbar []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SliceOfStruct struct {
|
|
||||||
Value []Basic
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tagged struct {
|
|
||||||
Extra string `mapstructure:"bar,what,what"`
|
|
||||||
Value string `mapstructure:"foo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TypeConversionResult struct {
|
|
||||||
IntToFloat float32
|
|
||||||
IntToUint uint
|
|
||||||
IntToBool bool
|
|
||||||
IntToString string
|
|
||||||
UintToInt int
|
|
||||||
UintToFloat float32
|
|
||||||
UintToBool bool
|
|
||||||
UintToString string
|
|
||||||
BoolToInt int
|
|
||||||
BoolToUint uint
|
|
||||||
BoolToFloat float32
|
|
||||||
BoolToString string
|
|
||||||
FloatToInt int
|
|
||||||
FloatToUint uint
|
|
||||||
FloatToBool bool
|
|
||||||
FloatToString string
|
|
||||||
SliceUint8ToString string
|
|
||||||
StringToInt int
|
|
||||||
StringToUint uint
|
|
||||||
StringToBool bool
|
|
||||||
StringToFloat float32
|
|
||||||
SliceToMap map[string]interface{}
|
|
||||||
MapToSlice []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBasicTypes(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vint": 42,
|
|
||||||
"Vuint": 42,
|
|
||||||
"vbool": true,
|
|
||||||
"Vfloat": 42.42,
|
|
||||||
"vsilent": true,
|
|
||||||
"vdata": 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("got an err: %s", err.Error())
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vstring != "foo" {
|
|
||||||
t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vint != 42 {
|
|
||||||
t.Errorf("vint value should be 42: %#v", result.Vint)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vuint != 42 {
|
|
||||||
t.Errorf("vuint value should be 42: %#v", result.Vuint)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbool != true {
|
|
||||||
t.Errorf("vbool value should be true: %#v", result.Vbool)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfloat != 42.42 {
|
|
||||||
t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vextra != "" {
|
|
||||||
t.Errorf("vextra value should be empty: %#v", result.Vextra)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.vsilent != false {
|
|
||||||
t.Error("vsilent should not be set, it is unexported")
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vdata != 42 {
|
|
||||||
t.Error("vdata should be valid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBasic_IntWithFloat(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vint": float64(42),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_Embedded(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"Basic": map[string]interface{}{
|
|
||||||
"vstring": "innerfoo",
|
|
||||||
},
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Embedded
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vstring != "innerfoo" {
|
|
||||||
t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vunique != "bar" {
|
|
||||||
t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_EmbeddedPointer(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"Basic": map[string]interface{}{
|
|
||||||
"vstring": "innerfoo",
|
|
||||||
},
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result EmbeddedPointer
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("should get error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_EmbeddedSquash(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result EmbeddedSquash
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vstring != "foo" {
|
|
||||||
t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vunique != "bar" {
|
|
||||||
t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_DecodeHook(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vint": "WHAT",
|
|
||||||
}
|
|
||||||
|
|
||||||
decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) {
|
|
||||||
if from == reflect.String && to != reflect.String {
|
|
||||||
return 5, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
config := &DecoderConfig{
|
|
||||||
DecodeHook: decodeHook,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vint != 5 {
|
|
||||||
t.Errorf("vint should be 5: %#v", result.Vint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_Nil(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
var input interface{} = nil
|
|
||||||
result := Basic{
|
|
||||||
Vstring: "foo",
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vstring != "foo" {
|
|
||||||
t.Fatalf("bad: %#v", result.Vstring)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_NonStruct(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
"bar": "baz",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result map[string]string
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result["foo"] != "bar" {
|
|
||||||
t.Fatal("foo is not bar")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecode_TypeConversion(t *testing.T) {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"IntToFloat": 42,
|
|
||||||
"IntToUint": 42,
|
|
||||||
"IntToBool": 1,
|
|
||||||
"IntToString": 42,
|
|
||||||
"UintToInt": 42,
|
|
||||||
"UintToFloat": 42,
|
|
||||||
"UintToBool": 42,
|
|
||||||
"UintToString": 42,
|
|
||||||
"BoolToInt": true,
|
|
||||||
"BoolToUint": true,
|
|
||||||
"BoolToFloat": true,
|
|
||||||
"BoolToString": true,
|
|
||||||
"FloatToInt": 42.42,
|
|
||||||
"FloatToUint": 42.42,
|
|
||||||
"FloatToBool": 42.42,
|
|
||||||
"FloatToString": 42.42,
|
|
||||||
"SliceUint8ToString": []uint8("foo"),
|
|
||||||
"StringToInt": "42",
|
|
||||||
"StringToUint": "42",
|
|
||||||
"StringToBool": "1",
|
|
||||||
"StringToFloat": "42.42",
|
|
||||||
"SliceToMap": []interface{}{},
|
|
||||||
"MapToSlice": map[string]interface{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedResultStrict := TypeConversionResult{
|
|
||||||
IntToFloat: 42.0,
|
|
||||||
IntToUint: 42,
|
|
||||||
UintToInt: 42,
|
|
||||||
UintToFloat: 42,
|
|
||||||
BoolToInt: 0,
|
|
||||||
BoolToUint: 0,
|
|
||||||
BoolToFloat: 0,
|
|
||||||
FloatToInt: 42,
|
|
||||||
FloatToUint: 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedResultWeak := TypeConversionResult{
|
|
||||||
IntToFloat: 42.0,
|
|
||||||
IntToUint: 42,
|
|
||||||
IntToBool: true,
|
|
||||||
IntToString: "42",
|
|
||||||
UintToInt: 42,
|
|
||||||
UintToFloat: 42,
|
|
||||||
UintToBool: true,
|
|
||||||
UintToString: "42",
|
|
||||||
BoolToInt: 1,
|
|
||||||
BoolToUint: 1,
|
|
||||||
BoolToFloat: 1,
|
|
||||||
BoolToString: "1",
|
|
||||||
FloatToInt: 42,
|
|
||||||
FloatToUint: 42,
|
|
||||||
FloatToBool: true,
|
|
||||||
FloatToString: "42.42",
|
|
||||||
SliceUint8ToString: "foo",
|
|
||||||
StringToInt: 42,
|
|
||||||
StringToUint: 42,
|
|
||||||
StringToBool: true,
|
|
||||||
StringToFloat: 42.42,
|
|
||||||
SliceToMap: map[string]interface{}{},
|
|
||||||
MapToSlice: []interface{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test strict type conversion
|
|
||||||
var resultStrict TypeConversionResult
|
|
||||||
err := Decode(input, &resultStrict)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("should return an error")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(resultStrict, expectedResultStrict) {
|
|
||||||
t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test weak type conversion
|
|
||||||
var decoder *Decoder
|
|
||||||
var resultWeak TypeConversionResult
|
|
||||||
|
|
||||||
config := &DecoderConfig{
|
|
||||||
WeaklyTypedInput: true,
|
|
||||||
Result: &resultWeak,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err = NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
|
|
||||||
t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecoder_ErrorUnused(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "hello",
|
|
||||||
"foo": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
config := &DecoderConfig{
|
|
||||||
ErrorUnused: true,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vother": map[interface{}]interface{}{
|
|
||||||
"foo": "foo",
|
|
||||||
"bar": "bar",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Map
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != "foo" {
|
|
||||||
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vother == nil {
|
|
||||||
t.Fatal("vother should not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result.Vother) != 2 {
|
|
||||||
t.Error("vother should have two items")
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vother["foo"] != "foo" {
|
|
||||||
t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"])
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vother["bar"] != "bar" {
|
|
||||||
t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMapOfStruct(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"value": map[string]interface{}{
|
|
||||||
"foo": map[string]string{"vstring": "one"},
|
|
||||||
"bar": map[string]string{"vstring": "two"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result MapOfStruct
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value == nil {
|
|
||||||
t.Fatal("value should not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result.Value) != 2 {
|
|
||||||
t.Error("value should have two items")
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value["foo"].Vstring != "one" {
|
|
||||||
t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value["bar"].Vstring != "two" {
|
|
||||||
t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNestedType(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vint": 42,
|
|
||||||
"vbool": true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Nested
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != "foo" {
|
|
||||||
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vstring != "foo" {
|
|
||||||
t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vint != 42 {
|
|
||||||
t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vbool != true {
|
|
||||||
t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vextra != "" {
|
|
||||||
t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNestedTypePointer(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": &map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vint": 42,
|
|
||||||
"vbool": true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result NestedPointer
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got an err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != "foo" {
|
|
||||||
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vstring != "foo" {
|
|
||||||
t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vint != 42 {
|
|
||||||
t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vbool != true {
|
|
||||||
t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar.Vextra != "" {
|
|
||||||
t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlice(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
inputStringSlice := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": []string{"foo", "bar", "baz"},
|
|
||||||
}
|
|
||||||
|
|
||||||
inputStringSlicePointer := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": &[]string{"foo", "bar", "baz"},
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStringSlice := &Slice{
|
|
||||||
"foo",
|
|
||||||
[]string{"foo", "bar", "baz"},
|
|
||||||
}
|
|
||||||
|
|
||||||
testSliceInput(t, inputStringSlice, outputStringSlice)
|
|
||||||
testSliceInput(t, inputStringSlicePointer, outputStringSlice)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvalidSlice(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
result := Slice{}
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSliceOfStruct(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"value": []map[string]interface{}{
|
|
||||||
{"vstring": "one"},
|
|
||||||
{"vstring": "two"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var result SliceOfStruct
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result.Value) != 2 {
|
|
||||||
t.Fatalf("expected two values, got %d", len(result.Value))
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value[0].Vstring != "one" {
|
|
||||||
t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value[1].Vstring != "two" {
|
|
||||||
t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvalidType(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Basic
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("error should exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
derr, ok := err.(*Error)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("error should be kind of Error, instead: %#v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" {
|
|
||||||
t.Errorf("got unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMetadata(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vfoo": "foo",
|
|
||||||
"vbar": map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"Vuint": 42,
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
"bar": "nil",
|
|
||||||
}
|
|
||||||
|
|
||||||
var md Metadata
|
|
||||||
var result Nested
|
|
||||||
config := &DecoderConfig{
|
|
||||||
Metadata: &md,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedKeys := []string{"Vfoo", "Vbar.Vstring", "Vbar.Vuint", "Vbar"}
|
|
||||||
if !reflect.DeepEqual(md.Keys, expectedKeys) {
|
|
||||||
t.Fatalf("bad keys: %#v", md.Keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedUnused := []string{"Vbar.foo", "bar"}
|
|
||||||
if !reflect.DeepEqual(md.Unused, expectedUnused) {
|
|
||||||
t.Fatalf("bad unused: %#v", md.Unused)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMetadata_Embedded(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"vstring": "foo",
|
|
||||||
"vunique": "bar",
|
|
||||||
}
|
|
||||||
|
|
||||||
var md Metadata
|
|
||||||
var result EmbeddedSquash
|
|
||||||
config := &DecoderConfig{
|
|
||||||
Metadata: &md,
|
|
||||||
Result: &result,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := NewDecoder(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = decoder.Decode(input)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedKeys := []string{"Vstring", "Vunique"}
|
|
||||||
|
|
||||||
sort.Strings(md.Keys)
|
|
||||||
if !reflect.DeepEqual(md.Keys, expectedKeys) {
|
|
||||||
t.Fatalf("bad keys: %#v", md.Keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedUnused := []string{}
|
|
||||||
if !reflect.DeepEqual(md.Unused, expectedUnused) {
|
|
||||||
t.Fatalf("bad unused: %#v", md.Unused)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNonPtrValue(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
err := Decode(map[string]interface{}{}, Basic{})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("error should exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err.Error() != "result must be a pointer" {
|
|
||||||
t.Errorf("got unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTagged(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
"bar": "value",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result Tagged
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Value != "bar" {
|
|
||||||
t.Errorf("value should be 'bar', got: %#v", result.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Extra != "value" {
|
|
||||||
t.Errorf("extra should be 'value', got: %#v", result.Extra)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWeakDecode(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"foo": "4",
|
|
||||||
"bar": "value",
|
|
||||||
}
|
|
||||||
|
|
||||||
var result struct {
|
|
||||||
Foo int
|
|
||||||
Bar string
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := WeakDecode(input, &result); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
if result.Foo != 4 {
|
|
||||||
t.Fatalf("bad: %#v", result)
|
|
||||||
}
|
|
||||||
if result.Bar != "value" {
|
|
||||||
t.Fatalf("bad: %#v", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
|
|
||||||
var result Slice
|
|
||||||
err := Decode(input, &result)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("got error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vfoo != expected.Vfoo {
|
|
||||||
t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Vbar == nil {
|
|
||||||
t.Fatalf("Vbar a slice, got '%#v'", result.Vbar)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result.Vbar) != len(expected.Vbar) {
|
|
||||||
t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, v := range result.Vbar {
|
|
||||||
if v != expected.Vbar[i] {
|
|
||||||
t.Errorf(
|
|
||||||
"Vbar[%d] should be '%#v', got '%#v'",
|
|
||||||
i, expected.Vbar[i], v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
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 2014 exoscale(tm)
|
||||||
|
|
||||||
|
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.
|
|
@ -1,70 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/snapshots"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSnapshots(t *testing.T) {
|
|
||||||
|
|
||||||
client, err := newClient(t)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
v, err := volumes.Create(client, &volumes.CreateOpts{
|
|
||||||
Name: "gophercloud-test-volume",
|
|
||||||
Size: 1,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = volumes.WaitForStatus(client, v.ID, "available", 120)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created volume: %v\n", v)
|
|
||||||
|
|
||||||
ss, err := snapshots.Create(client, &snapshots.CreateOpts{
|
|
||||||
Name: "gophercloud-test-snapshot",
|
|
||||||
VolumeID: v.ID,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = snapshots.WaitForStatus(client, ss.ID, "available", 120)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created snapshot: %+v\n", ss)
|
|
||||||
|
|
||||||
err = snapshots.Delete(client, ss.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = gophercloud.WaitFor(120, func() (bool, error) {
|
|
||||||
_, err := snapshots.Get(client, ss.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Log("Deleted snapshot\n")
|
|
||||||
|
|
||||||
err = volumes.Delete(client, v.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = gophercloud.WaitFor(120, func() (bool, error) {
|
|
||||||
_, err := volumes.Get(client, v.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Log("Deleted volume\n")
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
// +build acceptance blockstorage
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newClient(t *testing.T) (*gophercloud.ServiceClient, error) {
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
client, err := openstack.AuthenticatedClient(ao)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
return openstack.NewBlockStorageV1(client, gophercloud.EndpointOpts{
|
|
||||||
Region: os.Getenv("OS_REGION_NAME"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVolumes(t *testing.T) {
|
|
||||||
client, err := newClient(t)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
cv, err := volumes.Create(client, &volumes.CreateOpts{
|
|
||||||
Size: 1,
|
|
||||||
Name: "gophercloud-test-volume",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer func() {
|
|
||||||
err = volumes.WaitForStatus(client, cv.ID, "available", 60)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
err = volumes.Delete(client, cv.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = volumes.Update(client, cv.ID, &volumes.UpdateOpts{
|
|
||||||
Name: "gophercloud-updated-volume",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
v, err := volumes.Get(client, cv.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Got volume: %+v\n", v)
|
|
||||||
|
|
||||||
if v.Name != "gophercloud-updated-volume" {
|
|
||||||
t.Errorf("Unable to update volume: Expected name: gophercloud-updated-volume\nActual name: %s", v.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = volumes.List(client, &volumes.ListOpts{Name: "gophercloud-updated-volume"}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
vols, err := volumes.ExtractVolumes(page)
|
|
||||||
th.CheckEquals(t, 1, len(vols))
|
|
||||||
return true, err
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumetypes"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVolumeTypes(t *testing.T) {
|
|
||||||
client, err := newClient(t)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
vt, err := volumetypes.Create(client, &volumetypes.CreateOpts{
|
|
||||||
ExtraSpecs: map[string]interface{}{
|
|
||||||
"capabilities": "gpu",
|
|
||||||
"priority": 3,
|
|
||||||
},
|
|
||||||
Name: "gophercloud-test-volumeType",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer func() {
|
|
||||||
time.Sleep(10000 * time.Millisecond)
|
|
||||||
err = volumetypes.Delete(client, vt.ID).ExtractErr()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
t.Logf("Created volume type: %+v\n", vt)
|
|
||||||
|
|
||||||
vt, err = volumetypes.Get(client, vt.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Got volume type: %+v\n", vt)
|
|
||||||
|
|
||||||
err = volumetypes.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
volTypes, err := volumetypes.ExtractVolumeTypes(page)
|
|
||||||
if len(volTypes) != 1 {
|
|
||||||
t.Errorf("Expected 1 volume type, got %d", len(volTypes))
|
|
||||||
}
|
|
||||||
t.Logf("Listing volume types: %+v\n", volTypes)
|
|
||||||
return true, err
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package openstack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAuthenticatedClient(t *testing.T) {
|
|
||||||
// Obtain credentials from the environment.
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to acquire credentials: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := openstack.AuthenticatedClient(ao)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to authenticate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.TokenID == "" {
|
|
||||||
t.Errorf("No token ID assigned to the client")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Client successfully acquired a token: %v", client.TokenID)
|
|
||||||
|
|
||||||
// Find the storage service in the service catalog.
|
|
||||||
storage, err := openstack.NewObjectStorageV1(client, gophercloud.EndpointOpts{
|
|
||||||
Region: os.Getenv("OS_REGION_NAME"),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unable to locate a storage service: %v", err)
|
|
||||||
} else {
|
|
||||||
t.Logf("Located a storage service at endpoint: [%s]", storage.Endpoint)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBootFromVolume(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
name := tools.RandomString("Gophercloud-", 8)
|
|
||||||
t.Logf("Creating server [%s].", name)
|
|
||||||
|
|
||||||
bd := []bootfromvolume.BlockDevice{
|
|
||||||
bootfromvolume.BlockDevice{
|
|
||||||
UUID: choices.ImageID,
|
|
||||||
SourceType: bootfromvolume.Image,
|
|
||||||
VolumeSize: 10,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
serverCreateOpts := servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
}
|
|
||||||
server, err := bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
|
|
||||||
serverCreateOpts,
|
|
||||||
bd,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Created server: %+v\n", server)
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
t.Logf("Deleting server [%s]...", name)
|
|
||||||
}
|
|
104
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/compute_test.go
generated
vendored
104
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/compute_test.go
generated
vendored
|
@ -1,104 +0,0 @@
|
||||||
// +build acceptance common
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newClient() (*gophercloud.ServiceClient, error) {
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := openstack.AuthenticatedClient(ao)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return openstack.NewComputeV2(client, gophercloud.EndpointOpts{
|
|
||||||
Region: os.Getenv("OS_REGION_NAME"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForStatus(client *gophercloud.ServiceClient, server *servers.Server, status string) error {
|
|
||||||
return tools.WaitFor(func() (bool, error) {
|
|
||||||
latest, err := servers.Get(client, server.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if latest.Status == status {
|
|
||||||
// Success!
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeChoices contains image and flavor selections for use by the acceptance tests.
|
|
||||||
type ComputeChoices struct {
|
|
||||||
// ImageID contains the ID of a valid image.
|
|
||||||
ImageID string
|
|
||||||
|
|
||||||
// FlavorID contains the ID of a valid flavor.
|
|
||||||
FlavorID string
|
|
||||||
|
|
||||||
// FlavorIDResize contains the ID of a different flavor available on the same OpenStack installation, that is distinct
|
|
||||||
// from FlavorID.
|
|
||||||
FlavorIDResize string
|
|
||||||
|
|
||||||
// NetworkName is the name of a network to launch the instance on.
|
|
||||||
NetworkName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeChoicesFromEnv populates a ComputeChoices struct from environment variables.
|
|
||||||
// If any required state is missing, an `error` will be returned that enumerates the missing properties.
|
|
||||||
func ComputeChoicesFromEnv() (*ComputeChoices, error) {
|
|
||||||
imageID := os.Getenv("OS_IMAGE_ID")
|
|
||||||
flavorID := os.Getenv("OS_FLAVOR_ID")
|
|
||||||
flavorIDResize := os.Getenv("OS_FLAVOR_ID_RESIZE")
|
|
||||||
networkName := os.Getenv("OS_NETWORK_NAME")
|
|
||||||
|
|
||||||
missing := make([]string, 0, 3)
|
|
||||||
if imageID == "" {
|
|
||||||
missing = append(missing, "OS_IMAGE_ID")
|
|
||||||
}
|
|
||||||
if flavorID == "" {
|
|
||||||
missing = append(missing, "OS_FLAVOR_ID")
|
|
||||||
}
|
|
||||||
if flavorIDResize == "" {
|
|
||||||
missing = append(missing, "OS_FLAVOR_ID_RESIZE")
|
|
||||||
}
|
|
||||||
if networkName == "" {
|
|
||||||
networkName = "public"
|
|
||||||
}
|
|
||||||
|
|
||||||
notDistinct := ""
|
|
||||||
if flavorID == flavorIDResize {
|
|
||||||
notDistinct = "OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE must be distinct."
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(missing) > 0 || notDistinct != "" {
|
|
||||||
text := "You're missing some important setup:\n"
|
|
||||||
if len(missing) > 0 {
|
|
||||||
text += " * These environment variables must be provided: " + strings.Join(missing, ", ") + "\n"
|
|
||||||
}
|
|
||||||
if notDistinct != "" {
|
|
||||||
text += " * " + notDistinct + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ComputeChoices{ImageID: imageID, FlavorID: flavorID, FlavorIDResize: flavorIDResize, NetworkName: networkName}, nil
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
// +build acceptance compute extensionss
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListExtensions(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = extensions.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
exts, err := extensions.ExtractExtensions(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for i, ext := range exts {
|
|
||||||
t.Logf("[%02d] name=[%s]\n", i, ext.Name)
|
|
||||||
t.Logf(" alias=[%s]\n", ext.Alias)
|
|
||||||
t.Logf(" description=[%s]\n", ext.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetExtension(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
ext, err := extensions.Get(client, "os-admin-actions").Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Extension details:")
|
|
||||||
t.Logf(" name=[%s]\n", ext.Name)
|
|
||||||
t.Logf(" namespace=[%s]\n", ext.Namespace)
|
|
||||||
t.Logf(" alias=[%s]\n", ext.Alias)
|
|
||||||
t.Logf(" description=[%s]\n", ext.Description)
|
|
||||||
t.Logf(" updated=[%s]\n", ext.Updated)
|
|
||||||
}
|
|
57
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/flavors_test.go
generated
vendored
57
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/flavors_test.go
generated
vendored
|
@ -1,57 +0,0 @@
|
||||||
// +build acceptance compute flavors
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListFlavors(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("ID\tRegion\tName\tStatus\tCreated")
|
|
||||||
|
|
||||||
pager := flavors.ListDetail(client, nil)
|
|
||||||
count, pages := 0, 0
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("---")
|
|
||||||
pages++
|
|
||||||
flavors, err := flavors.ExtractFlavors(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range flavors {
|
|
||||||
t.Logf("%s\t%s\t%d\t%d\t%d", f.ID, f.Name, f.RAM, f.Disk, f.VCPUs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Logf("--------\n%d flavors listed on %d pages.", count, pages)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetFlavor(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flavor, err := flavors.Get(client, choices.FlavorID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to get flavor information: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Flavor: %#v", flavor)
|
|
||||||
}
|
|
107
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/floatingip_test.go
generated
vendored
107
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/floatingip_test.go
generated
vendored
|
@ -1,107 +0,0 @@
|
||||||
// +build acceptance compute servers
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func createFIPServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
name := tools.RandomString("ACPTTEST", 16)
|
|
||||||
t.Logf("Attempting to create server: %s\n", name)
|
|
||||||
|
|
||||||
pwd := tools.MakeNewPassword("")
|
|
||||||
|
|
||||||
server, err := servers.Create(client, servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
AdminPass: pwd,
|
|
||||||
}).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
th.AssertEquals(t, pwd, server.AdminPass)
|
|
||||||
|
|
||||||
return server, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFloatingIP(t *testing.T, client *gophercloud.ServiceClient) (*floatingip.FloatingIP, error) {
|
|
||||||
pool := os.Getenv("OS_POOL_NAME")
|
|
||||||
fip, err := floatingip.Create(client, &floatingip.CreateOpts{
|
|
||||||
Pool: pool,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Obtained Floating IP: %v", fip.IP)
|
|
||||||
|
|
||||||
return fip, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func associateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, serverId string, fip *floatingip.FloatingIP) {
|
|
||||||
err := floatingip.Associate(client, serverId, fip.IP).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Associated floating IP %v from instance %v", fip.IP, serverId)
|
|
||||||
defer func() {
|
|
||||||
err = floatingip.Disassociate(client, serverId, fip.IP).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Disassociated floating IP %v from instance %v", fip.IP, serverId)
|
|
||||||
}()
|
|
||||||
floatingIp, err := floatingip.Get(client, fip.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Floating IP %v is associated with Fixed IP %v", fip.IP, floatingIp.FixedIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFloatingIP(t *testing.T) {
|
|
||||||
pool := os.Getenv("OS_POOL_NAME")
|
|
||||||
if pool == "" {
|
|
||||||
t.Fatalf("OS_POOL_NAME must be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createFIPServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
servers.Delete(client, server.ID)
|
|
||||||
t.Logf("Server deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatalf("Unable to wait for server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fip, err := createFloatingIP(t, client)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create floating IP: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = floatingip.Delete(client, fip.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Floating IP deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
associateFloatingIP(t, client, server.ID, fip)
|
|
||||||
|
|
||||||
}
|
|
37
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/images_test.go
generated
vendored
37
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/images_test.go
generated
vendored
|
@ -1,37 +0,0 @@
|
||||||
// +build acceptance compute images
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListImages(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute: client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("ID\tRegion\tName\tStatus\tCreated")
|
|
||||||
|
|
||||||
pager := images.ListDetail(client, nil)
|
|
||||||
count, pages := 0, 0
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
pages++
|
|
||||||
images, err := images.ExtractImages(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, i := range images {
|
|
||||||
t.Logf("%s\t%s\t%s\t%s", i.ID, i.Name, i.Status, i.Created)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Logf("--------\n%d images listed on %d pages.", count, pages)
|
|
||||||
}
|
|
74
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/keypairs_test.go
generated
vendored
74
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/keypairs_test.go
generated
vendored
|
@ -1,74 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
|
|
||||||
"code.google.com/p/go.crypto/ssh"
|
|
||||||
)
|
|
||||||
|
|
||||||
const keyName = "gophercloud_test_key_pair"
|
|
||||||
|
|
||||||
func TestCreateServerWithKeyPair(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
publicKey := privateKey.PublicKey
|
|
||||||
pub, err := ssh.NewPublicKey(&publicKey)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
pubBytes := ssh.MarshalAuthorizedKey(pub)
|
|
||||||
pk := string(pubBytes)
|
|
||||||
|
|
||||||
kp, err := keypairs.Create(client, keypairs.CreateOpts{
|
|
||||||
Name: keyName,
|
|
||||||
PublicKey: pk,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created key pair: %s\n", kp)
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
name := tools.RandomString("Gophercloud-", 8)
|
|
||||||
t.Logf("Creating server [%s] with key pair.", name)
|
|
||||||
|
|
||||||
serverCreateOpts := servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := servers.Create(client, keypairs.CreateOptsExt{
|
|
||||||
serverCreateOpts,
|
|
||||||
keyName,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatalf("Unable to wait for server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err = servers.Get(client, server.ID).Extract()
|
|
||||||
t.Logf("Created server: %+v\n", server)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, server.KeyName, keyName)
|
|
||||||
|
|
||||||
t.Logf("Deleting key pair [%s]...", kp.Name)
|
|
||||||
err = keypairs.Delete(client, keyName).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Deleting server [%s]...", name)
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
// +build acceptance compute defsecrules
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
dsr "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSecDefRules(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
id := createDefRule(t, client)
|
|
||||||
|
|
||||||
listDefRules(t, client)
|
|
||||||
|
|
||||||
getDefRule(t, client, id)
|
|
||||||
|
|
||||||
deleteDefRule(t, client, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDefRule(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
opts := dsr.CreateOpts{
|
|
||||||
FromPort: tools.RandomInt(80, 89),
|
|
||||||
ToPort: tools.RandomInt(90, 99),
|
|
||||||
IPProtocol: "TCP",
|
|
||||||
CIDR: "0.0.0.0/0",
|
|
||||||
}
|
|
||||||
|
|
||||||
rule, err := dsr.Create(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created default rule %s", rule.ID)
|
|
||||||
|
|
||||||
return rule.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listDefRules(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
err := dsr.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
drList, err := dsr.ExtractDefaultRules(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, dr := range drList {
|
|
||||||
t.Logf("Listing default rule %s: Name [%s] From Port [%s] To Port [%s] Protocol [%s]",
|
|
||||||
dr.ID, dr.FromPort, dr.ToPort, dr.IPProtocol)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDefRule(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
rule, err := dsr.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting rule %s: %#v", id, rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteDefRule(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
err := dsr.Delete(client, id).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Deleted rule %s", id)
|
|
||||||
}
|
|
177
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secgroup_test.go
generated
vendored
177
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secgroup_test.go
generated
vendored
|
@ -1,177 +0,0 @@
|
||||||
// +build acceptance compute secgroups
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSecGroups(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
serverID, needsDeletion := findServer(t, client)
|
|
||||||
|
|
||||||
groupID := createSecGroup(t, client)
|
|
||||||
|
|
||||||
listSecGroups(t, client)
|
|
||||||
|
|
||||||
newName := tools.RandomString("secgroup_", 5)
|
|
||||||
updateSecGroup(t, client, groupID, newName)
|
|
||||||
|
|
||||||
getSecGroup(t, client, groupID)
|
|
||||||
|
|
||||||
addRemoveRules(t, client, groupID)
|
|
||||||
|
|
||||||
addServerToSecGroup(t, client, serverID, newName)
|
|
||||||
|
|
||||||
removeServerFromSecGroup(t, client, serverID, newName)
|
|
||||||
|
|
||||||
if needsDeletion {
|
|
||||||
servers.Delete(client, serverID)
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteSecGroup(t, client, groupID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSecGroup(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
opts := secgroups.CreateOpts{
|
|
||||||
Name: tools.RandomString("secgroup_", 5),
|
|
||||||
Description: "something",
|
|
||||||
}
|
|
||||||
|
|
||||||
group, err := secgroups.Create(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created secgroup %s %s", group.ID, group.Name)
|
|
||||||
|
|
||||||
return group.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listSecGroups(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
err := secgroups.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
secGrpList, err := secgroups.ExtractSecurityGroups(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, sg := range secGrpList {
|
|
||||||
t.Logf("Listing secgroup %s: Name [%s] Desc [%s] TenantID [%s]", sg.ID,
|
|
||||||
sg.Name, sg.Description, sg.TenantID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateSecGroup(t *testing.T, client *gophercloud.ServiceClient, id, newName string) {
|
|
||||||
opts := secgroups.UpdateOpts{
|
|
||||||
Name: newName,
|
|
||||||
Description: tools.RandomString("dec_", 10),
|
|
||||||
}
|
|
||||||
group, err := secgroups.Update(client, id, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Updated %s's name to %s", group.ID, group.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
group, err := secgroups.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting %s: %#v", id, group)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRemoveRules(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
opts := secgroups.CreateRuleOpts{
|
|
||||||
ParentGroupID: id,
|
|
||||||
FromPort: 22,
|
|
||||||
ToPort: 22,
|
|
||||||
IPProtocol: "TCP",
|
|
||||||
CIDR: "0.0.0.0/0",
|
|
||||||
}
|
|
||||||
|
|
||||||
rule, err := secgroups.CreateRule(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Adding rule %s to group %s", rule.ID, id)
|
|
||||||
|
|
||||||
err = secgroups.DeleteRule(client, rule.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Deleted rule %s from group %s", rule.ID, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findServer(t *testing.T, client *gophercloud.ServiceClient) (string, bool) {
|
|
||||||
var serverID string
|
|
||||||
var needsDeletion bool
|
|
||||||
|
|
||||||
err := servers.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
sList, err := servers.ExtractServers(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, s := range sList {
|
|
||||||
serverID = s.ID
|
|
||||||
needsDeletion = false
|
|
||||||
|
|
||||||
t.Logf("Found an existing server: ID [%s]", serverID)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if serverID == "" {
|
|
||||||
t.Log("No server found, creating one")
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
opts := &servers.CreateOpts{
|
|
||||||
Name: tools.RandomString("secgroup_test_", 5),
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := servers.Create(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
serverID = s.ID
|
|
||||||
|
|
||||||
t.Logf("Created server %s, waiting for it to build", s.ID)
|
|
||||||
err = servers.WaitForStatus(client, serverID, "ACTIVE", 300)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
needsDeletion = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return serverID, needsDeletion
|
|
||||||
}
|
|
||||||
|
|
||||||
func addServerToSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
|
|
||||||
err := secgroups.AddServerToGroup(client, serverID, groupName).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Adding group %s to server %s", groupName, serverID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeServerFromSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
|
|
||||||
err := secgroups.RemoveServerFromGroup(client, serverID, groupName).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Removing group %s from server %s", groupName, serverID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
err := secgroups.Delete(client, id).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Deleted group %s", id)
|
|
||||||
}
|
|
478
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/servers_test.go
generated
vendored
478
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/servers_test.go
generated
vendored
|
@ -1,478 +0,0 @@
|
||||||
// +build acceptance compute servers
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListServers(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("ID\tRegion\tName\tStatus\tIPv4\tIPv6")
|
|
||||||
|
|
||||||
pager := servers.List(client, servers.ListOpts{})
|
|
||||||
count, pages := 0, 0
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
pages++
|
|
||||||
t.Logf("---")
|
|
||||||
|
|
||||||
servers, err := servers.ExtractServers(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range servers {
|
|
||||||
t.Logf("%s\t%s\t%s\t%s\t%s\t\n", s.ID, s.Name, s.Status, s.AccessIPv4, s.AccessIPv6)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Logf("--------\n%d servers listed on %d pages.\n", count, pages)
|
|
||||||
}
|
|
||||||
|
|
||||||
func networkingClient() (*gophercloud.ServiceClient, error) {
|
|
||||||
opts, err := openstack.AuthOptionsFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
provider, err := openstack.AuthenticatedClient(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
|
|
||||||
Region: os.Getenv("OS_REGION_NAME"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
var network networks.Network
|
|
||||||
|
|
||||||
networkingClient, err := networkingClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a networking client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pager := networks.List(networkingClient, networks.ListOpts{
|
|
||||||
Name: choices.NetworkName,
|
|
||||||
Limit: 1,
|
|
||||||
})
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
networks, err := networks.ExtractNetworks(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract networks: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(networks) == 0 {
|
|
||||||
t.Fatalf("No networks to attach to server")
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
network = networks[0]
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
name := tools.RandomString("ACPTTEST", 16)
|
|
||||||
t.Logf("Attempting to create server: %s\n", name)
|
|
||||||
|
|
||||||
pwd := tools.MakeNewPassword("")
|
|
||||||
|
|
||||||
server, err := servers.Create(client, servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
Networks: []servers.Network{
|
|
||||||
servers.Network{UUID: network.ID},
|
|
||||||
},
|
|
||||||
AdminPass: pwd,
|
|
||||||
}).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
th.AssertEquals(t, pwd, server.AdminPass)
|
|
||||||
|
|
||||||
return server, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateDestroyServer(t *testing.T) {
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
servers.Delete(client, server.ID)
|
|
||||||
t.Logf("Server deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatalf("Unable to wait for server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pager := servers.ListAddresses(client, server.ID)
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
networks, err := servers.ExtractAddresses(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for n, a := range networks {
|
|
||||||
t.Logf("%s: %+v\n", n, a)
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
pager = servers.ListAddressesByNetwork(client, server.ID, choices.NetworkName)
|
|
||||||
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
addresses, err := servers.ExtractNetworkAddresses(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, a := range addresses {
|
|
||||||
t.Logf("%+v\n", a)
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateServer(t *testing.T) {
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
alternateName := tools.RandomString("ACPTTEST", 16)
|
|
||||||
for alternateName == server.Name {
|
|
||||||
alternateName = tools.RandomString("ACPTTEST", 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Attempting to rename the server to %s.", alternateName)
|
|
||||||
|
|
||||||
updated, err := servers.Update(client, server.ID, servers.UpdateOpts{Name: alternateName}).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to rename server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if updated.ID != server.ID {
|
|
||||||
t.Errorf("Updated server ID [%s] didn't match original server ID [%s]!", updated.ID, server.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tools.WaitFor(func() (bool, error) {
|
|
||||||
latest, err := servers.Get(client, updated.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return latest.Name == alternateName, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActionChangeAdminPassword(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
randomPassword := tools.MakeNewPassword(server.AdminPass)
|
|
||||||
res := servers.ChangeAdminPassword(client, server.ID, randomPassword)
|
|
||||||
if res.Err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "PASSWORD"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActionReboot(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res := servers.Reboot(client, server.ID, "aldhjflaskhjf")
|
|
||||||
if res.Err == nil {
|
|
||||||
t.Fatal("Expected the SDK to provide an ArgumentError here")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Attempting reboot of server %s", server.ID)
|
|
||||||
res = servers.Reboot(client, server.ID, servers.OSReboot)
|
|
||||||
if res.Err != nil {
|
|
||||||
t.Fatalf("Unable to reboot server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "REBOOT"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActionRebuild(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Attempting to rebuild server %s", server.ID)
|
|
||||||
|
|
||||||
rebuildOpts := servers.RebuildOpts{
|
|
||||||
Name: tools.RandomString("ACPTTEST", 16),
|
|
||||||
AdminPass: tools.MakeNewPassword(server.AdminPass),
|
|
||||||
ImageID: choices.ImageID,
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuilt, err := servers.Rebuild(client, server.ID, rebuildOpts).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rebuilt.ID != server.ID {
|
|
||||||
t.Errorf("Expected rebuilt server ID of [%s]; got [%s]", server.ID, rebuilt.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, rebuilt, "REBUILD"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, rebuilt, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) {
|
|
||||||
if err := waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Attempting to resize server [%s]", server.ID)
|
|
||||||
|
|
||||||
opts := &servers.ResizeOpts{
|
|
||||||
FlavorRef: choices.FlavorIDResize,
|
|
||||||
}
|
|
||||||
if res := servers.Resize(client, server.ID, opts); res.Err != nil {
|
|
||||||
t.Fatal(res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActionResizeConfirm(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
resizeServer(t, client, server, choices)
|
|
||||||
|
|
||||||
t.Logf("Attempting to confirm resize for server %s", server.ID)
|
|
||||||
|
|
||||||
if res := servers.ConfirmResize(client, server.ID); res.Err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActionResizeRevert(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
resizeServer(t, client, server, choices)
|
|
||||||
|
|
||||||
t.Logf("Attempting to revert resize for server %s", server.ID)
|
|
||||||
|
|
||||||
if res := servers.RevertResize(client, server.ID); res.Err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServerMetadata(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createServer(t, client, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer servers.Delete(client, server.ID)
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata, err := servers.UpdateMetadata(client, server.ID, servers.MetadataOpts{
|
|
||||||
"foo": "bar",
|
|
||||||
"this": "that",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("UpdateMetadata result: %+v\n", metadata)
|
|
||||||
|
|
||||||
err = servers.DeleteMetadatum(client, server.ID, "foo").ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
metadata, err = servers.CreateMetadatum(client, server.ID, servers.MetadatumOpts{
|
|
||||||
"foo": "baz",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("CreateMetadatum result: %+v\n", metadata)
|
|
||||||
|
|
||||||
metadata, err = servers.Metadatum(client, server.ID, "foo").Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Metadatum result: %+v\n", metadata)
|
|
||||||
th.AssertEquals(t, "baz", metadata["foo"])
|
|
||||||
|
|
||||||
metadata, err = servers.Metadata(client, server.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Metadata result: %+v\n", metadata)
|
|
||||||
|
|
||||||
metadata, err = servers.ResetMetadata(client, server.ID, servers.MetadataOpts{}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("ResetMetadata result: %+v\n", metadata)
|
|
||||||
th.AssertDeepEquals(t, map[string]string{}, metadata)
|
|
||||||
}
|
|
|
@ -1,109 +0,0 @@
|
||||||
// +build acceptance compute servers
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getNetworkID(t *testing.T, client *gophercloud.ServiceClient, networkName string) (string, error) {
|
|
||||||
allPages, err := tenantnetworks.List(client).AllPages()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to list networks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
networkList, err := tenantnetworks.ExtractNetworks(allPages)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to list networks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
networkID := ""
|
|
||||||
for _, network := range networkList {
|
|
||||||
t.Logf("Network: %v", network)
|
|
||||||
if network.Name == networkName {
|
|
||||||
networkID = network.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Found network ID for %s: %s\n", networkName, networkID)
|
|
||||||
|
|
||||||
return networkID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNetworkServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices, networkID string) (*servers.Server, error) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
name := tools.RandomString("ACPTTEST", 16)
|
|
||||||
t.Logf("Attempting to create server: %s\n", name)
|
|
||||||
|
|
||||||
pwd := tools.MakeNewPassword("")
|
|
||||||
|
|
||||||
networks := make([]servers.Network, 1)
|
|
||||||
networks[0] = servers.Network{
|
|
||||||
UUID: networkID,
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := servers.Create(client, servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
AdminPass: pwd,
|
|
||||||
Networks: networks,
|
|
||||||
}).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
th.AssertEquals(t, pwd, server.AdminPass)
|
|
||||||
|
|
||||||
return server, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTenantNetworks(t *testing.T) {
|
|
||||||
networkName := os.Getenv("OS_NETWORK_NAME")
|
|
||||||
if networkName == "" {
|
|
||||||
t.Fatalf("OS_NETWORK_NAME must be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
networkID, err := getNetworkID(t, client, networkName)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to get network ID: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createNetworkServer(t, client, choices, networkID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
servers.Delete(client, server.ID)
|
|
||||||
t.Logf("Server deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatalf("Unable to wait for server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
allPages, err := tenantnetworks.List(client).AllPages()
|
|
||||||
allNetworks, err := tenantnetworks.ExtractNetworks(allPages)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Retrieved all %d networks: %+v", len(allNetworks), allNetworks)
|
|
||||||
}
|
|
125
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/volumeattach_test.go
generated
vendored
125
vendor/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/volumeattach_test.go
generated
vendored
|
@ -1,125 +0,0 @@
|
||||||
// +build acceptance compute servers
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newBlockClient(t *testing.T) (*gophercloud.ServiceClient, error) {
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
client, err := openstack.AuthenticatedClient(ao)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
return openstack.NewBlockStorageV1(client, gophercloud.EndpointOpts{
|
|
||||||
Region: os.Getenv("OS_REGION_NAME"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVAServer(t *testing.T, computeClient *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test that requires server creation in short mode.")
|
|
||||||
}
|
|
||||||
|
|
||||||
name := tools.RandomString("ACPTTEST", 16)
|
|
||||||
t.Logf("Attempting to create server: %s\n", name)
|
|
||||||
|
|
||||||
pwd := tools.MakeNewPassword("")
|
|
||||||
|
|
||||||
server, err := servers.Create(computeClient, servers.CreateOpts{
|
|
||||||
Name: name,
|
|
||||||
FlavorRef: choices.FlavorID,
|
|
||||||
ImageRef: choices.ImageID,
|
|
||||||
AdminPass: pwd,
|
|
||||||
}).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
th.AssertEquals(t, pwd, server.AdminPass)
|
|
||||||
|
|
||||||
return server, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVAVolume(t *testing.T, blockClient *gophercloud.ServiceClient) (*volumes.Volume, error) {
|
|
||||||
volume, err := volumes.Create(blockClient, &volumes.CreateOpts{
|
|
||||||
Size: 1,
|
|
||||||
Name: "gophercloud-test-volume",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer func() {
|
|
||||||
err = volumes.WaitForStatus(blockClient, volume.ID, "available", 60)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return volume, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVolumeAttachment(t *testing.T, computeClient *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, serverId string, volumeId string) {
|
|
||||||
va, err := volumeattach.Create(computeClient, serverId, &volumeattach.CreateOpts{
|
|
||||||
VolumeID: volumeId,
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer func() {
|
|
||||||
err = volumes.WaitForStatus(blockClient, volumeId, "in-use", 60)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
err = volumeattach.Delete(computeClient, serverId, va.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
err = volumes.WaitForStatus(blockClient, volumeId, "available", 60)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAttachVolume(t *testing.T) {
|
|
||||||
choices, err := ComputeChoicesFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
computeClient, err := newClient()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a compute client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
blockClient, err := newBlockClient(t)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create a blockstorage client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := createVAServer(t, computeClient, choices)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
servers.Delete(computeClient, server.ID)
|
|
||||||
t.Logf("Server deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = waitForStatus(computeClient, server, "ACTIVE"); err != nil {
|
|
||||||
t.Fatalf("Unable to wait for server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
volume, err := createVAVolume(t, blockClient)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create volume: %v", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = volumes.Delete(blockClient, volume.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Volume deleted.")
|
|
||||||
}()
|
|
||||||
|
|
||||||
createVolumeAttachment(t, computeClient, blockClient, server.ID, volume.ID)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// +build acceptance identity
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
extensions2 "github.com/rackspace/gophercloud/openstack/identity/v2/extensions"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEnumerateExtensions(t *testing.T) {
|
|
||||||
service := authenticatedClient(t)
|
|
||||||
|
|
||||||
t.Logf("Extensions available on this identity endpoint:")
|
|
||||||
count := 0
|
|
||||||
err := extensions2.List(service).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page %02d ---", count)
|
|
||||||
|
|
||||||
extensions, err := extensions2.ExtractExtensions(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for i, ext := range extensions {
|
|
||||||
t.Logf("[%02d] name=[%s] namespace=[%s]", i, ext.Name, ext.Namespace)
|
|
||||||
t.Logf(" alias=[%s] updated=[%s]", ext.Alias, ext.Updated)
|
|
||||||
t.Logf(" description=[%s]", ext.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
count++
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetExtension(t *testing.T) {
|
|
||||||
service := authenticatedClient(t)
|
|
||||||
|
|
||||||
ext, err := extensions2.Get(service, "OS-KSCRUD").Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
th.CheckEquals(t, "OpenStack Keystone User CRUD", ext.Name)
|
|
||||||
th.CheckEquals(t, "http://docs.openstack.org/identity/api/ext/OS-KSCRUD/v1.0", ext.Namespace)
|
|
||||||
th.CheckEquals(t, "OS-KSCRUD", ext.Alias)
|
|
||||||
th.CheckEquals(t, "OpenStack extensions to Keystone v2.0 API enabling User Operations.", ext.Description)
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
// +build acceptance identity
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func v2AuthOptions(t *testing.T) gophercloud.AuthOptions {
|
|
||||||
// Obtain credentials from the environment.
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// Trim out unused fields. Prefer authentication by API key to password.
|
|
||||||
ao.UserID, ao.DomainID, ao.DomainName = "", "", ""
|
|
||||||
if ao.APIKey != "" {
|
|
||||||
ao.Password = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return ao
|
|
||||||
}
|
|
||||||
|
|
||||||
func createClient(t *testing.T, auth bool) *gophercloud.ServiceClient {
|
|
||||||
ao := v2AuthOptions(t)
|
|
||||||
|
|
||||||
provider, err := openstack.NewClient(ao.IdentityEndpoint)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if auth {
|
|
||||||
err = openstack.AuthenticateV2(provider, ao)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return openstack.NewIdentityV2(provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unauthenticatedClient(t *testing.T) *gophercloud.ServiceClient {
|
|
||||||
return createClient(t, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func authenticatedClient(t *testing.T) *gophercloud.ServiceClient {
|
|
||||||
return createClient(t, true)
|
|
||||||
}
|
|
58
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/role_test.go
generated
vendored
58
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/role_test.go
generated
vendored
|
@ -1,58 +0,0 @@
|
||||||
// +build acceptance identity roles
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/identity/v2/extensions/admin/roles"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRoles(t *testing.T) {
|
|
||||||
client := authenticatedClient(t)
|
|
||||||
|
|
||||||
tenantID := findTenant(t, client)
|
|
||||||
userID := createUser(t, client, tenantID)
|
|
||||||
roleID := listRoles(t, client)
|
|
||||||
|
|
||||||
addUserRole(t, client, tenantID, userID, roleID)
|
|
||||||
|
|
||||||
deleteUserRole(t, client, tenantID, userID, roleID)
|
|
||||||
|
|
||||||
deleteUser(t, client, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listRoles(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
var roleID string
|
|
||||||
|
|
||||||
err := roles.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
roleList, err := roles.ExtractRoles(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, role := range roleList {
|
|
||||||
t.Logf("Listing role: ID [%s] Name [%s]", role.ID, role.Name)
|
|
||||||
roleID = role.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
return roleID
|
|
||||||
}
|
|
||||||
|
|
||||||
func addUserRole(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID, roleID string) {
|
|
||||||
err := roles.AddUserRole(client, tenantID, userID, roleID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Added role %s to user %s", roleID, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteUserRole(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID, roleID string) {
|
|
||||||
err := roles.DeleteUserRole(client, tenantID, userID, roleID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Removed role %s from user %s", roleID, userID)
|
|
||||||
}
|
|
32
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/tenant_test.go
generated
vendored
32
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/tenant_test.go
generated
vendored
|
@ -1,32 +0,0 @@
|
||||||
// +build acceptance identity
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
tenants2 "github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEnumerateTenants(t *testing.T) {
|
|
||||||
service := authenticatedClient(t)
|
|
||||||
|
|
||||||
t.Logf("Tenants to which your current token grants access:")
|
|
||||||
count := 0
|
|
||||||
err := tenants2.List(service, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page %02d ---", count)
|
|
||||||
|
|
||||||
tenants, err := tenants2.ExtractTenants(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for i, tenant := range tenants {
|
|
||||||
t.Logf("[%02d] name=[%s] id=[%s] description=[%s] enabled=[%v]",
|
|
||||||
i, tenant.Name, tenant.ID, tenant.Description, tenant.Enabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
count++
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
38
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/token_test.go
generated
vendored
38
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/token_test.go
generated
vendored
|
@ -1,38 +0,0 @@
|
||||||
// +build acceptance identity
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAuthenticate(t *testing.T) {
|
|
||||||
ao := v2AuthOptions(t)
|
|
||||||
service := unauthenticatedClient(t)
|
|
||||||
|
|
||||||
// Authenticated!
|
|
||||||
result := tokens2.Create(service, tokens2.WrapOptions(ao))
|
|
||||||
|
|
||||||
// Extract and print the token.
|
|
||||||
token, err := result.ExtractToken()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Acquired token: [%s]", token.ID)
|
|
||||||
t.Logf("The token will expire at: [%s]", token.ExpiresAt.String())
|
|
||||||
t.Logf("The token is valid for tenant: [%#v]", token.Tenant)
|
|
||||||
|
|
||||||
// Extract and print the service catalog.
|
|
||||||
catalog, err := result.ExtractServiceCatalog()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Acquired service catalog listing [%d] services", len(catalog.Entries))
|
|
||||||
for i, entry := range catalog.Entries {
|
|
||||||
t.Logf("[%02d]: name=[%s], type=[%s]", i, entry.Name, entry.Type)
|
|
||||||
for _, endpoint := range entry.Endpoints {
|
|
||||||
t.Logf(" - region=[%s] publicURL=[%s]", endpoint.Region, endpoint.PublicURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
127
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/user_test.go
generated
vendored
127
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/user_test.go
generated
vendored
|
@ -1,127 +0,0 @@
|
||||||
// +build acceptance identity
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/identity/v2/users"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUsers(t *testing.T) {
|
|
||||||
client := authenticatedClient(t)
|
|
||||||
|
|
||||||
tenantID := findTenant(t, client)
|
|
||||||
|
|
||||||
userID := createUser(t, client, tenantID)
|
|
||||||
|
|
||||||
listUsers(t, client)
|
|
||||||
|
|
||||||
getUser(t, client, userID)
|
|
||||||
|
|
||||||
updateUser(t, client, userID)
|
|
||||||
|
|
||||||
listUserRoles(t, client, tenantID, userID)
|
|
||||||
|
|
||||||
deleteUser(t, client, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findTenant(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
var tenantID string
|
|
||||||
err := tenants.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
tenantList, err := tenants.ExtractTenants(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, t := range tenantList {
|
|
||||||
tenantID = t.ID
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
return tenantID
|
|
||||||
}
|
|
||||||
|
|
||||||
func createUser(t *testing.T, client *gophercloud.ServiceClient, tenantID string) string {
|
|
||||||
t.Log("Creating user")
|
|
||||||
|
|
||||||
opts := users.CreateOpts{
|
|
||||||
Name: tools.RandomString("user_", 5),
|
|
||||||
Enabled: users.Disabled,
|
|
||||||
TenantID: tenantID,
|
|
||||||
Email: "new_user@foo.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := users.Create(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created user %s on tenant %s", user.ID, tenantID)
|
|
||||||
|
|
||||||
return user.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listUsers(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
err := users.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
userList, err := users.ExtractUsers(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, user := range userList {
|
|
||||||
t.Logf("Listing user: ID [%s] Name [%s] Email [%s] Enabled? [%s]",
|
|
||||||
user.ID, user.Name, user.Email, strconv.FormatBool(user.Enabled))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
|
||||||
_, err := users.Get(client, userID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting user %s", userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
|
||||||
opts := users.UpdateOpts{Name: tools.RandomString("new_name", 5), Email: "new@foo.com"}
|
|
||||||
user, err := users.Update(client, userID, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Updated user %s: Name [%s] Email [%s]", userID, user.Name, user.Email)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listUserRoles(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID string) {
|
|
||||||
count := 0
|
|
||||||
err := users.ListRoles(client, tenantID, userID).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
count++
|
|
||||||
|
|
||||||
roleList, err := users.ExtractRoles(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Listing roles for user %s", userID)
|
|
||||||
|
|
||||||
for _, r := range roleList {
|
|
||||||
t.Logf("- %s (%s)", r.Name, r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
t.Logf("No roles for user %s", userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
|
||||||
res := users.Delete(client, userID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted user %s", userID)
|
|
||||||
}
|
|
111
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/endpoint_test.go
generated
vendored
111
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/endpoint_test.go
generated
vendored
|
@ -1,111 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
endpoints3 "github.com/rackspace/gophercloud/openstack/identity/v3/endpoints"
|
|
||||||
services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListEndpoints(t *testing.T) {
|
|
||||||
// Create a service client.
|
|
||||||
serviceClient := createAuthenticatedClient(t)
|
|
||||||
if serviceClient == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the service to list all available endpoints.
|
|
||||||
pager := endpoints3.List(serviceClient, endpoints3.ListOpts{})
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
endpoints, err := endpoints3.ExtractEndpoints(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error extracting endpoings: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, endpoint := range endpoints {
|
|
||||||
t.Logf("Endpoint: %8s %10s %9s %s",
|
|
||||||
endpoint.ID,
|
|
||||||
endpoint.Availability,
|
|
||||||
endpoint.Name,
|
|
||||||
endpoint.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error while iterating endpoint pages: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNavigateCatalog(t *testing.T) {
|
|
||||||
// Create a service client.
|
|
||||||
client := createAuthenticatedClient(t)
|
|
||||||
if client == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var compute *services3.Service
|
|
||||||
var endpoint *endpoints3.Endpoint
|
|
||||||
|
|
||||||
// Discover the service we're interested in.
|
|
||||||
servicePager := services3.List(client, services3.ListOpts{ServiceType: "compute"})
|
|
||||||
err := servicePager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
part, err := services3.ExtractServices(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if compute != nil {
|
|
||||||
t.Fatalf("Expected one service, got more than one page")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if len(part) != 1 {
|
|
||||||
t.Fatalf("Expected one service, got %d", len(part))
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
compute = &part[0]
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error iterating pages: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if compute == nil {
|
|
||||||
t.Fatalf("No compute service found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enumerate the endpoints available for this service.
|
|
||||||
computePager := endpoints3.List(client, endpoints3.ListOpts{
|
|
||||||
Availability: gophercloud.AvailabilityPublic,
|
|
||||||
ServiceID: compute.ID,
|
|
||||||
})
|
|
||||||
err = computePager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
part, err := endpoints3.ExtractEndpoints(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if endpoint != nil {
|
|
||||||
t.Fatalf("Expected one endpoint, got more than one page")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if len(part) != 1 {
|
|
||||||
t.Fatalf("Expected one endpoint, got %d", len(part))
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint = &part[0]
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if endpoint == nil {
|
|
||||||
t.Fatalf("No endpoint found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Success. The compute endpoint is at %s.", endpoint.URL)
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func createAuthenticatedClient(t *testing.T) *gophercloud.ServiceClient {
|
|
||||||
// Obtain credentials from the environment.
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// Trim out unused fields.
|
|
||||||
ao.Username, ao.TenantID, ao.TenantName = "", "", ""
|
|
||||||
|
|
||||||
if ao.UserID == "" {
|
|
||||||
t.Logf("Skipping identity v3 tests because no OS_USERID is present.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a client and manually authenticate against v3.
|
|
||||||
providerClient, err := openstack.NewClient(ao.IdentityEndpoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to instantiate client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = openstack.AuthenticateV3(providerClient, ao)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to authenticate against identity v3: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a service client.
|
|
||||||
return openstack.NewIdentityV3(providerClient)
|
|
||||||
}
|
|
36
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/service_test.go
generated
vendored
36
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/service_test.go
generated
vendored
|
@ -1,36 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListServices(t *testing.T) {
|
|
||||||
// Create a service client.
|
|
||||||
serviceClient := createAuthenticatedClient(t)
|
|
||||||
if serviceClient == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the client to list all available services.
|
|
||||||
pager := services3.List(serviceClient, services3.ListOpts{})
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
parts, err := services3.ExtractServices(page)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
for _, service := range parts {
|
|
||||||
t.Logf("Service: %32s %15s %10s %s", service.ID, service.Type, service.Name, *service.Description)
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error traversing pages: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
42
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/token_test.go
generated
vendored
42
vendor/github.com/rackspace/gophercloud/acceptance/openstack/identity/v3/token_test.go
generated
vendored
|
@ -1,42 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack"
|
|
||||||
tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetToken(t *testing.T) {
|
|
||||||
// Obtain credentials from the environment.
|
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to acquire credentials: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim out unused fields. Skip if we don't have a UserID.
|
|
||||||
ao.Username, ao.TenantID, ao.TenantName = "", "", ""
|
|
||||||
if ao.UserID == "" {
|
|
||||||
t.Logf("Skipping identity v3 tests because no OS_USERID is present.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an unauthenticated client.
|
|
||||||
provider, err := openstack.NewClient(ao.IdentityEndpoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to instantiate client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a service client.
|
|
||||||
service := openstack.NewIdentityV3(provider)
|
|
||||||
|
|
||||||
// Use the service to create a token.
|
|
||||||
token, err := tokens3.Create(service, ao, nil).Extract()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to get token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Acquired token: %s", token.ID)
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/apiversions"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListAPIVersions(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
pager := apiversions.ListVersions(Client)
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
versions, err := apiversions.ExtractAPIVersions(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, v := range versions {
|
|
||||||
t.Logf("API Version: ID [%s] Status [%s]", v.ID, v.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListAPIResources(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
pager := apiversions.ListVersionResources(Client, "v2.0")
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
vrs, err := apiversions.ExtractVersionResources(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, vr := range vrs {
|
|
||||||
t.Logf("Network: Name [%s] Collection [%s]", vr.Name, vr.Collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListExts(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
pager := extensions.List(Client)
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
exts, err := extensions.ExtractExtensions(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, ext := range exts {
|
|
||||||
t.Logf("Extension: Name [%s] Description [%s]", ext.Name, ext.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetExt(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
ext, err := extensions.Get(Client, "service-type").Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
th.AssertEquals(t, ext.Updated, "2013-01-20T00:00:00-00:00")
|
|
||||||
th.AssertEquals(t, ext.Name, "Neutron Service Type Management")
|
|
||||||
th.AssertEquals(t, ext.Namespace, "http://docs.openstack.org/ext/neutron/service-type/api/v1.0")
|
|
||||||
th.AssertEquals(t, ext.Alias, "service-type")
|
|
||||||
th.AssertEquals(t, ext.Description, "API for retrieving service providers for Neutron advanced services")
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
// +build acceptance networking fwaas
|
|
||||||
|
|
||||||
package fwaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func firewallSetup(t *testing.T) string {
|
|
||||||
base.Setup(t)
|
|
||||||
return createPolicy(t, &policies.CreateOpts{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func firewallTeardown(t *testing.T, policyID string) {
|
|
||||||
defer base.Teardown()
|
|
||||||
deletePolicy(t, policyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFirewall(t *testing.T) {
|
|
||||||
policyID := firewallSetup(t)
|
|
||||||
defer firewallTeardown(t, policyID)
|
|
||||||
|
|
||||||
firewallID := createFirewall(t, &firewalls.CreateOpts{
|
|
||||||
Name: "gophercloud test",
|
|
||||||
Description: "acceptance test",
|
|
||||||
PolicyID: policyID,
|
|
||||||
})
|
|
||||||
|
|
||||||
waitForFirewallToBeActive(t, firewallID)
|
|
||||||
|
|
||||||
listFirewalls(t)
|
|
||||||
|
|
||||||
updateFirewall(t, firewallID, &firewalls.UpdateOpts{
|
|
||||||
Description: "acceptance test updated",
|
|
||||||
})
|
|
||||||
|
|
||||||
waitForFirewallToBeActive(t, firewallID)
|
|
||||||
|
|
||||||
deleteFirewall(t, firewallID)
|
|
||||||
|
|
||||||
waitForFirewallToBeDeleted(t, firewallID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFirewall(t *testing.T, opts *firewalls.CreateOpts) string {
|
|
||||||
f, err := firewalls.Create(base.Client, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created firewall: %#v", opts)
|
|
||||||
return f.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listFirewalls(t *testing.T) {
|
|
||||||
err := firewalls.List(base.Client, firewalls.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
firewallList, err := firewalls.ExtractFirewalls(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract firewalls: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range firewallList {
|
|
||||||
t.Logf("Listing firewalls: ID [%s]", r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateFirewall(t *testing.T, firewallID string, opts *firewalls.UpdateOpts) {
|
|
||||||
f, err := firewalls.Update(base.Client, firewallID, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Updated firewall ID [%s]", f.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFirewall(t *testing.T, firewallID string) *firewalls.Firewall {
|
|
||||||
f, err := firewalls.Get(base.Client, firewallID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting firewall ID [%s]", f.ID)
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteFirewall(t *testing.T, firewallID string) {
|
|
||||||
res := firewalls.Delete(base.Client, firewallID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted firewall %s", firewallID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForFirewallToBeActive(t *testing.T, firewallID string) {
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
fw := getFirewall(t, firewallID)
|
|
||||||
if fw.Status == "ACTIVE" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForFirewallToBeDeleted(t *testing.T, firewallID string) {
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
err := firewalls.Get(base.Client, firewallID).Err
|
|
||||||
if err != nil {
|
|
||||||
httpStatus := err.(*gophercloud.UnexpectedResponseCodeError)
|
|
||||||
if httpStatus.Actual == 404 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
// +build acceptance networking fwaas
|
|
||||||
|
|
||||||
package fwaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func firewallPolicySetup(t *testing.T) string {
|
|
||||||
base.Setup(t)
|
|
||||||
return createRule(t, &rules.CreateOpts{
|
|
||||||
Protocol: "tcp",
|
|
||||||
Action: "allow",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func firewallPolicyTeardown(t *testing.T, ruleID string) {
|
|
||||||
defer base.Teardown()
|
|
||||||
deleteRule(t, ruleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFirewallPolicy(t *testing.T) {
|
|
||||||
ruleID := firewallPolicySetup(t)
|
|
||||||
defer firewallPolicyTeardown(t, ruleID)
|
|
||||||
|
|
||||||
policyID := createPolicy(t, &policies.CreateOpts{
|
|
||||||
Name: "gophercloud test",
|
|
||||||
Description: "acceptance test",
|
|
||||||
Rules: []string{
|
|
||||||
ruleID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
listPolicies(t)
|
|
||||||
|
|
||||||
updatePolicy(t, policyID, &policies.UpdateOpts{
|
|
||||||
Description: "acceptance test updated",
|
|
||||||
})
|
|
||||||
|
|
||||||
getPolicy(t, policyID)
|
|
||||||
|
|
||||||
removeRuleFromPolicy(t, policyID, ruleID)
|
|
||||||
|
|
||||||
addRuleToPolicy(t, policyID, ruleID)
|
|
||||||
|
|
||||||
deletePolicy(t, policyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPolicy(t *testing.T, opts *policies.CreateOpts) string {
|
|
||||||
p, err := policies.Create(base.Client, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created policy: %#v", opts)
|
|
||||||
return p.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listPolicies(t *testing.T) {
|
|
||||||
err := policies.List(base.Client, policies.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
policyList, err := policies.ExtractPolicies(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract policies: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range policyList {
|
|
||||||
t.Logf("Listing policies: ID [%s]", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updatePolicy(t *testing.T, policyID string, opts *policies.UpdateOpts) {
|
|
||||||
p, err := policies.Update(base.Client, policyID, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Updated policy ID [%s]", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeRuleFromPolicy(t *testing.T, policyID string, ruleID string) {
|
|
||||||
err := policies.RemoveRule(base.Client, policyID, ruleID)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Removed rule [%s] from policy ID [%s]", ruleID, policyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRuleToPolicy(t *testing.T, policyID string, ruleID string) {
|
|
||||||
err := policies.InsertRule(base.Client, policyID, ruleID, "", "")
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Inserted rule [%s] into policy ID [%s]", ruleID, policyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPolicy(t *testing.T, policyID string) {
|
|
||||||
p, err := policies.Get(base.Client, policyID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting policy ID [%s]", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deletePolicy(t *testing.T, policyID string) {
|
|
||||||
res := policies.Delete(base.Client, policyID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted policy %s", policyID)
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
// +build acceptance networking fwaas
|
|
||||||
|
|
||||||
package fwaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFirewallRules(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
ruleID := createRule(t, &rules.CreateOpts{
|
|
||||||
Name: "gophercloud_test",
|
|
||||||
Description: "acceptance test",
|
|
||||||
Protocol: "tcp",
|
|
||||||
Action: "allow",
|
|
||||||
DestinationIPAddress: "192.168.0.0/24",
|
|
||||||
DestinationPort: "22",
|
|
||||||
})
|
|
||||||
|
|
||||||
listRules(t)
|
|
||||||
|
|
||||||
destinationIPAddress := "192.168.1.0/24"
|
|
||||||
destinationPort := ""
|
|
||||||
sourcePort := "1234"
|
|
||||||
|
|
||||||
updateRule(t, ruleID, &rules.UpdateOpts{
|
|
||||||
DestinationIPAddress: &destinationIPAddress,
|
|
||||||
DestinationPort: &destinationPort,
|
|
||||||
SourcePort: &sourcePort,
|
|
||||||
})
|
|
||||||
|
|
||||||
getRule(t, ruleID)
|
|
||||||
|
|
||||||
deleteRule(t, ruleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createRule(t *testing.T, opts *rules.CreateOpts) string {
|
|
||||||
r, err := rules.Create(base.Client, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created rule: %#v", opts)
|
|
||||||
return r.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listRules(t *testing.T) {
|
|
||||||
err := rules.List(base.Client, rules.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
ruleList, err := rules.ExtractRules(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract rules: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range ruleList {
|
|
||||||
t.Logf("Listing rules: ID [%s]", r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRule(t *testing.T, ruleID string, opts *rules.UpdateOpts) {
|
|
||||||
r, err := rules.Update(base.Client, ruleID, *opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Updated rule ID [%s]", r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRule(t *testing.T, ruleID string) {
|
|
||||||
r, err := rules.Get(base.Client, ruleID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting rule ID [%s]", r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteRule(t *testing.T, ruleID string) {
|
|
||||||
res := rules.Delete(base.Client, ruleID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted rule %s", ruleID)
|
|
||||||
}
|
|
|
@ -1,300 +0,0 @@
|
||||||
// +build acceptance networking layer3ext
|
|
||||||
|
|
||||||
package extensions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/external"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
cidr1 = "10.0.0.1/24"
|
|
||||||
cidr2 = "20.0.0.1/24"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
testRouter(t)
|
|
||||||
testFloatingIP(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testRouter(t *testing.T) {
|
|
||||||
// Setup: Create network
|
|
||||||
networkID := createNetwork(t)
|
|
||||||
|
|
||||||
// Create router
|
|
||||||
routerID := createRouter(t, networkID)
|
|
||||||
|
|
||||||
// Lists routers
|
|
||||||
listRouters(t)
|
|
||||||
|
|
||||||
// Update router
|
|
||||||
updateRouter(t, routerID)
|
|
||||||
|
|
||||||
// Get router
|
|
||||||
getRouter(t, routerID)
|
|
||||||
|
|
||||||
// Create new subnet. Note: this subnet will be deleted when networkID is deleted
|
|
||||||
subnetID := createSubnet(t, networkID, cidr2)
|
|
||||||
|
|
||||||
// Add interface
|
|
||||||
addInterface(t, routerID, subnetID)
|
|
||||||
|
|
||||||
// Remove interface
|
|
||||||
removeInterface(t, routerID, subnetID)
|
|
||||||
|
|
||||||
// Delete router
|
|
||||||
deleteRouter(t, routerID)
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
deleteNetwork(t, networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFloatingIP(t *testing.T) {
|
|
||||||
// Setup external network
|
|
||||||
extNetworkID := createNetwork(t)
|
|
||||||
|
|
||||||
// Setup internal network, subnet and port
|
|
||||||
intNetworkID, subnetID, portID := createInternalTopology(t)
|
|
||||||
|
|
||||||
// Now the important part: we need to allow the external network to talk to
|
|
||||||
// the internal subnet. For this we need a router that has an interface to
|
|
||||||
// the internal subnet.
|
|
||||||
routerID := bridgeIntSubnetWithExtNetwork(t, extNetworkID, subnetID)
|
|
||||||
|
|
||||||
// Create floating IP
|
|
||||||
ipID := createFloatingIP(t, extNetworkID, portID)
|
|
||||||
|
|
||||||
// Get floating IP
|
|
||||||
getFloatingIP(t, ipID)
|
|
||||||
|
|
||||||
// Update floating IP
|
|
||||||
updateFloatingIP(t, ipID, portID)
|
|
||||||
|
|
||||||
// Delete floating IP
|
|
||||||
deleteFloatingIP(t, ipID)
|
|
||||||
|
|
||||||
// Remove the internal subnet interface
|
|
||||||
removeInterface(t, routerID, subnetID)
|
|
||||||
|
|
||||||
// Delete router and external network
|
|
||||||
deleteRouter(t, routerID)
|
|
||||||
deleteNetwork(t, extNetworkID)
|
|
||||||
|
|
||||||
// Delete internal port and network
|
|
||||||
deletePort(t, portID)
|
|
||||||
deleteNetwork(t, intNetworkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNetwork(t *testing.T) string {
|
|
||||||
t.Logf("Creating a network")
|
|
||||||
|
|
||||||
asu := true
|
|
||||||
opts := external.CreateOpts{
|
|
||||||
Parent: networks.CreateOpts{Name: "sample_network", AdminStateUp: &asu},
|
|
||||||
External: true,
|
|
||||||
}
|
|
||||||
n, err := networks.Create(base.Client, opts).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if n.ID == "" {
|
|
||||||
t.Fatalf("No ID returned when creating a network")
|
|
||||||
}
|
|
||||||
|
|
||||||
createSubnet(t, n.ID, cidr1)
|
|
||||||
|
|
||||||
t.Logf("Network created: ID [%s]", n.ID)
|
|
||||||
|
|
||||||
return n.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteNetwork(t *testing.T, networkID string) {
|
|
||||||
t.Logf("Deleting network %s", networkID)
|
|
||||||
networks.Delete(base.Client, networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deletePort(t *testing.T, portID string) {
|
|
||||||
t.Logf("Deleting port %s", portID)
|
|
||||||
ports.Delete(base.Client, portID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createInternalTopology(t *testing.T) (string, string, string) {
|
|
||||||
t.Logf("Creating an internal network (for port)")
|
|
||||||
opts := networks.CreateOpts{Name: "internal_network"}
|
|
||||||
n, err := networks.Create(base.Client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// A subnet is also needed
|
|
||||||
subnetID := createSubnet(t, n.ID, cidr2)
|
|
||||||
|
|
||||||
t.Logf("Creating an internal port on network %s", n.ID)
|
|
||||||
p, err := ports.Create(base.Client, ports.CreateOpts{
|
|
||||||
NetworkID: n.ID,
|
|
||||||
Name: "fixed_internal_port",
|
|
||||||
}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
return n.ID, subnetID, p.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func bridgeIntSubnetWithExtNetwork(t *testing.T, networkID, subnetID string) string {
|
|
||||||
// Create router with external gateway info
|
|
||||||
routerID := createRouter(t, networkID)
|
|
||||||
|
|
||||||
// Add interface for internal subnet
|
|
||||||
addInterface(t, routerID, subnetID)
|
|
||||||
|
|
||||||
return routerID
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSubnet(t *testing.T, networkID, cidr string) string {
|
|
||||||
t.Logf("Creating a subnet for network %s", networkID)
|
|
||||||
|
|
||||||
iFalse := false
|
|
||||||
s, err := subnets.Create(base.Client, subnets.CreateOpts{
|
|
||||||
NetworkID: networkID,
|
|
||||||
CIDR: cidr,
|
|
||||||
IPVersion: subnets.IPv4,
|
|
||||||
Name: "my_subnet",
|
|
||||||
EnableDHCP: &iFalse,
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Subnet created: ID [%s]", s.ID)
|
|
||||||
|
|
||||||
return s.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func createRouter(t *testing.T, networkID string) string {
|
|
||||||
t.Logf("Creating a router for network %s", networkID)
|
|
||||||
|
|
||||||
asu := false
|
|
||||||
gwi := routers.GatewayInfo{NetworkID: networkID}
|
|
||||||
r, err := routers.Create(base.Client, routers.CreateOpts{
|
|
||||||
Name: "foo_router",
|
|
||||||
AdminStateUp: &asu,
|
|
||||||
GatewayInfo: &gwi,
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
if r.ID == "" {
|
|
||||||
t.Fatalf("No ID returned when creating a router")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Router created: ID [%s]", r.ID)
|
|
||||||
|
|
||||||
return r.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listRouters(t *testing.T) {
|
|
||||||
pager := routers.List(base.Client, routers.ListOpts{})
|
|
||||||
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
routerList, err := routers.ExtractRouters(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, r := range routerList {
|
|
||||||
t.Logf("Listing router: ID [%s] Name [%s] Status [%s] GatewayInfo [%#v]",
|
|
||||||
r.ID, r.Name, r.Status, r.GatewayInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRouter(t *testing.T, routerID string) {
|
|
||||||
_, err := routers.Update(base.Client, routerID, routers.UpdateOpts{
|
|
||||||
Name: "another_name",
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRouter(t *testing.T, routerID string) {
|
|
||||||
r, err := routers.Get(base.Client, routerID).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting router: ID [%s] Name [%s] Status [%s]", r.ID, r.Name, r.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addInterface(t *testing.T, routerID, subnetID string) {
|
|
||||||
ir, err := routers.AddInterface(base.Client, routerID, routers.InterfaceOpts{SubnetID: subnetID}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Interface added to router %s: SubnetID [%s] PortID [%s]", routerID, ir.SubnetID, ir.PortID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeInterface(t *testing.T, routerID, subnetID string) {
|
|
||||||
ir, err := routers.RemoveInterface(base.Client, routerID, routers.InterfaceOpts{SubnetID: subnetID}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Interface %s removed from %s", ir.ID, routerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteRouter(t *testing.T, routerID string) {
|
|
||||||
t.Logf("Deleting router %s", routerID)
|
|
||||||
|
|
||||||
res := routers.Delete(base.Client, routerID)
|
|
||||||
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFloatingIP(t *testing.T, networkID, portID string) string {
|
|
||||||
t.Logf("Creating floating IP on network [%s] with port [%s]", networkID, portID)
|
|
||||||
|
|
||||||
opts := floatingips.CreateOpts{
|
|
||||||
FloatingNetworkID: networkID,
|
|
||||||
PortID: portID,
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, err := floatingips.Create(base.Client, opts).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Floating IP created: ID [%s] Status [%s] Fixed (internal) IP: [%s] Floating (external) IP: [%s]",
|
|
||||||
ip.ID, ip.Status, ip.FixedIP, ip.FloatingIP)
|
|
||||||
|
|
||||||
return ip.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFloatingIP(t *testing.T, ipID string) {
|
|
||||||
ip, err := floatingips.Get(base.Client, ipID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting floating IP: ID [%s] Status [%s]", ip.ID, ip.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateFloatingIP(t *testing.T, ipID, portID string) {
|
|
||||||
t.Logf("Disassociate all ports from IP %s", ipID)
|
|
||||||
_, err := floatingips.Update(base.Client, ipID, floatingips.UpdateOpts{PortID: ""}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Re-associate the port %s", portID)
|
|
||||||
_, err = floatingips.Update(base.Client, ipID, floatingips.UpdateOpts{PortID: portID}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteFloatingIP(t *testing.T, ipID string) {
|
|
||||||
t.Logf("Deleting IP %s", ipID)
|
|
||||||
res := floatingips.Delete(base.Client, ipID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
// +build acceptance networking lbaas lbaasmember
|
|
||||||
|
|
||||||
package lbaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMembers(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// setup
|
|
||||||
networkID, subnetID := SetupTopology(t)
|
|
||||||
poolID := CreatePool(t, subnetID)
|
|
||||||
|
|
||||||
// create member
|
|
||||||
memberID := createMember(t, poolID)
|
|
||||||
|
|
||||||
// list members
|
|
||||||
listMembers(t)
|
|
||||||
|
|
||||||
// update member
|
|
||||||
updateMember(t, memberID)
|
|
||||||
|
|
||||||
// get member
|
|
||||||
getMember(t, memberID)
|
|
||||||
|
|
||||||
// delete member
|
|
||||||
deleteMember(t, memberID)
|
|
||||||
|
|
||||||
// teardown
|
|
||||||
DeletePool(t, poolID)
|
|
||||||
DeleteTopology(t, networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createMember(t *testing.T, poolID string) string {
|
|
||||||
m, err := members.Create(base.Client, members.CreateOpts{
|
|
||||||
Address: "192.168.199.1",
|
|
||||||
ProtocolPort: 8080,
|
|
||||||
PoolID: poolID,
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created member: ID [%s] Status [%s] Weight [%d] Address [%s] Port [%d]",
|
|
||||||
m.ID, m.Status, m.Weight, m.Address, m.ProtocolPort)
|
|
||||||
|
|
||||||
return m.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMembers(t *testing.T) {
|
|
||||||
err := members.List(base.Client, members.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
memberList, err := members.ExtractMembers(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract members: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range memberList {
|
|
||||||
t.Logf("Listing member: ID [%s] Status [%s]", m.ID, m.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateMember(t *testing.T, memberID string) {
|
|
||||||
m, err := members.Update(base.Client, memberID, members.UpdateOpts{AdminStateUp: true}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Updated member ID [%s]", m.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMember(t *testing.T, memberID string) {
|
|
||||||
m, err := members.Get(base.Client, memberID).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting member ID [%s]", m.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteMember(t *testing.T, memberID string) {
|
|
||||||
res := members.Delete(base.Client, memberID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted member %s", memberID)
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
// +build acceptance networking lbaas lbaasmonitor
|
|
||||||
|
|
||||||
package lbaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMonitors(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// create monitor
|
|
||||||
monitorID := CreateMonitor(t)
|
|
||||||
|
|
||||||
// list monitors
|
|
||||||
listMonitors(t)
|
|
||||||
|
|
||||||
// update monitor
|
|
||||||
updateMonitor(t, monitorID)
|
|
||||||
|
|
||||||
// get monitor
|
|
||||||
getMonitor(t, monitorID)
|
|
||||||
|
|
||||||
// delete monitor
|
|
||||||
deleteMonitor(t, monitorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitors(t *testing.T) {
|
|
||||||
err := monitors.List(base.Client, monitors.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
monitorList, err := monitors.ExtractMonitors(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract monitors: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range monitorList {
|
|
||||||
t.Logf("Listing monitor: ID [%s] Type [%s] Delay [%ds] Timeout [%d] Retries [%d] Status [%s]",
|
|
||||||
m.ID, m.Type, m.Delay, m.Timeout, m.MaxRetries, m.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateMonitor(t *testing.T, monitorID string) {
|
|
||||||
opts := monitors.UpdateOpts{Delay: 10, Timeout: 10, MaxRetries: 3}
|
|
||||||
m, err := monitors.Update(base.Client, monitorID, opts).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Updated monitor ID [%s]", m.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMonitor(t *testing.T, monitorID string) {
|
|
||||||
m, err := monitors.Get(base.Client, monitorID).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting monitor ID [%s]: URL path [%s] HTTP Method [%s] Accepted codes [%s]",
|
|
||||||
m.ID, m.URLPath, m.HTTPMethod, m.ExpectedCodes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteMonitor(t *testing.T, monitorID string) {
|
|
||||||
res := monitors.Delete(base.Client, monitorID)
|
|
||||||
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
|
|
||||||
t.Logf("Deleted monitor %s", monitorID)
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
// +build acceptance networking lbaas lbaaspool
|
|
||||||
|
|
||||||
package lbaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPools(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// setup
|
|
||||||
networkID, subnetID := SetupTopology(t)
|
|
||||||
|
|
||||||
// create pool
|
|
||||||
poolID := CreatePool(t, subnetID)
|
|
||||||
|
|
||||||
// list pools
|
|
||||||
listPools(t)
|
|
||||||
|
|
||||||
// update pool
|
|
||||||
updatePool(t, poolID)
|
|
||||||
|
|
||||||
// get pool
|
|
||||||
getPool(t, poolID)
|
|
||||||
|
|
||||||
// create monitor
|
|
||||||
monitorID := CreateMonitor(t)
|
|
||||||
|
|
||||||
// associate health monitor
|
|
||||||
associateMonitor(t, poolID, monitorID)
|
|
||||||
|
|
||||||
// disassociate health monitor
|
|
||||||
disassociateMonitor(t, poolID, monitorID)
|
|
||||||
|
|
||||||
// delete pool
|
|
||||||
DeletePool(t, poolID)
|
|
||||||
|
|
||||||
// teardown
|
|
||||||
DeleteTopology(t, networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listPools(t *testing.T) {
|
|
||||||
err := pools.List(base.Client, pools.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
poolList, err := pools.ExtractPools(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract pools: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range poolList {
|
|
||||||
t.Logf("Listing pool: ID [%s] Name [%s] Status [%s] LB algorithm [%s]", p.ID, p.Name, p.Status, p.LBMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updatePool(t *testing.T, poolID string) {
|
|
||||||
opts := pools.UpdateOpts{Name: "SuperPool", LBMethod: pools.LBMethodLeastConnections}
|
|
||||||
p, err := pools.Update(base.Client, poolID, opts).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Updated pool ID [%s]", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPool(t *testing.T, poolID string) {
|
|
||||||
p, err := pools.Get(base.Client, poolID).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting pool ID [%s]", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func associateMonitor(t *testing.T, poolID, monitorID string) {
|
|
||||||
res := pools.AssociateMonitor(base.Client, poolID, monitorID)
|
|
||||||
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
|
|
||||||
t.Logf("Associated pool %s with monitor %s", poolID, monitorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func disassociateMonitor(t *testing.T, poolID, monitorID string) {
|
|
||||||
res := pools.DisassociateMonitor(base.Client, poolID, monitorID)
|
|
||||||
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
|
|
||||||
t.Logf("Disassociated pool %s with monitor %s", poolID, monitorID)
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
// +build acceptance networking lbaas lbaasvip
|
|
||||||
|
|
||||||
package lbaas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVIPs(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// setup
|
|
||||||
networkID, subnetID := SetupTopology(t)
|
|
||||||
poolID := CreatePool(t, subnetID)
|
|
||||||
|
|
||||||
// create VIP
|
|
||||||
VIPID := createVIP(t, subnetID, poolID)
|
|
||||||
|
|
||||||
// list VIPs
|
|
||||||
listVIPs(t)
|
|
||||||
|
|
||||||
// update VIP
|
|
||||||
updateVIP(t, VIPID)
|
|
||||||
|
|
||||||
// get VIP
|
|
||||||
getVIP(t, VIPID)
|
|
||||||
|
|
||||||
// delete VIP
|
|
||||||
deleteVIP(t, VIPID)
|
|
||||||
|
|
||||||
// teardown
|
|
||||||
DeletePool(t, poolID)
|
|
||||||
DeleteTopology(t, networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVIP(t *testing.T, subnetID, poolID string) string {
|
|
||||||
p, err := vips.Create(base.Client, vips.CreateOpts{
|
|
||||||
Protocol: "HTTP",
|
|
||||||
Name: "New_VIP",
|
|
||||||
AdminStateUp: vips.Up,
|
|
||||||
SubnetID: subnetID,
|
|
||||||
PoolID: poolID,
|
|
||||||
ProtocolPort: 80,
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created pool %s", p.ID)
|
|
||||||
|
|
||||||
return p.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listVIPs(t *testing.T) {
|
|
||||||
err := vips.List(base.Client, vips.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
vipList, err := vips.ExtractVIPs(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract VIPs: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vip := range vipList {
|
|
||||||
t.Logf("Listing VIP: ID [%s] Name [%s] Address [%s] Port [%s] Connection Limit [%d]",
|
|
||||||
vip.ID, vip.Name, vip.Address, vip.ProtocolPort, vip.ConnLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateVIP(t *testing.T, VIPID string) {
|
|
||||||
i1000 := 1000
|
|
||||||
_, err := vips.Update(base.Client, VIPID, vips.UpdateOpts{ConnLimit: &i1000}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Updated VIP ID [%s]", VIPID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getVIP(t *testing.T, VIPID string) {
|
|
||||||
vip, err := vips.Get(base.Client, VIPID).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Getting VIP ID [%s]: Status [%s]", vip.ID, vip.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteVIP(t *testing.T, VIPID string) {
|
|
||||||
res := vips.Delete(base.Client, VIPID)
|
|
||||||
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
|
|
||||||
t.Logf("Deleted VIP %s", VIPID)
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package extensions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNetworkCRUDOperations(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// Create a network
|
|
||||||
n, err := networks.Create(base.Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: networks.Up}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, n.Name, "sample_network")
|
|
||||||
th.AssertEquals(t, n.AdminStateUp, true)
|
|
||||||
networkID := n.ID
|
|
||||||
|
|
||||||
// List networks
|
|
||||||
pager := networks.List(base.Client, networks.ListOpts{Limit: 2})
|
|
||||||
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
networkList, err := networks.ExtractNetworks(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, n := range networkList {
|
|
||||||
t.Logf("Network: ID [%s] Name [%s] Status [%s] Is shared? [%s]",
|
|
||||||
n.ID, n.Name, n.Status, strconv.FormatBool(n.Shared))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
|
|
||||||
// Get a network
|
|
||||||
if networkID == "" {
|
|
||||||
t.Fatalf("In order to retrieve a network, the NetworkID must be set")
|
|
||||||
}
|
|
||||||
n, err = networks.Get(base.Client, networkID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, n.Status, "ACTIVE")
|
|
||||||
th.AssertDeepEquals(t, n.Subnets, []string{})
|
|
||||||
th.AssertEquals(t, n.Name, "sample_network")
|
|
||||||
th.AssertEquals(t, n.AdminStateUp, true)
|
|
||||||
th.AssertEquals(t, n.Shared, false)
|
|
||||||
th.AssertEquals(t, n.ID, networkID)
|
|
||||||
|
|
||||||
// Update network
|
|
||||||
n, err = networks.Update(base.Client, networkID, networks.UpdateOpts{Name: "new_network_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, n.Name, "new_network_name")
|
|
||||||
|
|
||||||
// Delete network
|
|
||||||
res := networks.Delete(base.Client, networkID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateMultipleNetworks(t *testing.T) {
|
|
||||||
//networks.CreateMany()
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
// +build acceptance networking security
|
|
||||||
|
|
||||||
package extensions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSecurityGroups(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// create security group
|
|
||||||
groupID := createSecGroup(t)
|
|
||||||
|
|
||||||
// delete security group
|
|
||||||
defer deleteSecGroup(t, groupID)
|
|
||||||
|
|
||||||
// list security group
|
|
||||||
listSecGroups(t)
|
|
||||||
|
|
||||||
// get security group
|
|
||||||
getSecGroup(t, groupID)
|
|
||||||
|
|
||||||
// create port with security group
|
|
||||||
networkID, portID := createPort(t, groupID)
|
|
||||||
|
|
||||||
// teardown
|
|
||||||
defer deleteNetwork(t, networkID)
|
|
||||||
|
|
||||||
// delete port
|
|
||||||
defer deletePort(t, portID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSecurityGroupRules(t *testing.T) {
|
|
||||||
base.Setup(t)
|
|
||||||
defer base.Teardown()
|
|
||||||
|
|
||||||
// create security group
|
|
||||||
groupID := createSecGroup(t)
|
|
||||||
|
|
||||||
defer deleteSecGroup(t, groupID)
|
|
||||||
|
|
||||||
// create security group rule
|
|
||||||
ruleID := createSecRule(t, groupID)
|
|
||||||
|
|
||||||
// delete security group rule
|
|
||||||
defer deleteSecRule(t, ruleID)
|
|
||||||
|
|
||||||
// list security group rule
|
|
||||||
listSecRules(t)
|
|
||||||
|
|
||||||
// get security group rule
|
|
||||||
getSecRule(t, ruleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSecGroup(t *testing.T) string {
|
|
||||||
sg, err := groups.Create(base.Client, groups.CreateOpts{
|
|
||||||
Name: "new-webservers",
|
|
||||||
Description: "security group for webservers",
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created security group %s", sg.ID)
|
|
||||||
|
|
||||||
return sg.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listSecGroups(t *testing.T) {
|
|
||||||
err := groups.List(base.Client, groups.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
list, err := groups.ExtractGroups(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract secgroups: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sg := range list {
|
|
||||||
t.Logf("Listing security group: ID [%s] Name [%s]", sg.ID, sg.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSecGroup(t *testing.T, id string) {
|
|
||||||
sg, err := groups.Get(base.Client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting security group: ID [%s] Name [%s] Description [%s]", sg.ID, sg.Name, sg.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPort(t *testing.T, groupID string) (string, string) {
|
|
||||||
n, err := networks.Create(base.Client, networks.CreateOpts{Name: "tmp_network"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created network %s", n.ID)
|
|
||||||
|
|
||||||
opts := ports.CreateOpts{
|
|
||||||
NetworkID: n.ID,
|
|
||||||
Name: "my_port",
|
|
||||||
SecurityGroups: []string{groupID},
|
|
||||||
}
|
|
||||||
p, err := ports.Create(base.Client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created port %s with security group %s", p.ID, groupID)
|
|
||||||
|
|
||||||
return n.ID, p.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteSecGroup(t *testing.T, groupID string) {
|
|
||||||
res := groups.Delete(base.Client, groupID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted security group %s", groupID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSecRule(t *testing.T, groupID string) string {
|
|
||||||
r, err := rules.Create(base.Client, rules.CreateOpts{
|
|
||||||
Direction: "ingress",
|
|
||||||
PortRangeMin: 80,
|
|
||||||
EtherType: "IPv4",
|
|
||||||
PortRangeMax: 80,
|
|
||||||
Protocol: "tcp",
|
|
||||||
SecGroupID: groupID,
|
|
||||||
}).Extract()
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Created security group rule %s", r.ID)
|
|
||||||
|
|
||||||
return r.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listSecRules(t *testing.T) {
|
|
||||||
err := rules.List(base.Client, rules.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
list, err := rules.ExtractRules(page)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to extract sec rules: %v", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range list {
|
|
||||||
t.Logf("Listing security rule: ID [%s]", r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSecRule(t *testing.T, id string) {
|
|
||||||
r, err := rules.Get(base.Client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Getting security rule: ID [%s] Direction [%s] EtherType [%s] Protocol [%s]",
|
|
||||||
r.ID, r.Direction, r.EtherType, r.Protocol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteSecRule(t *testing.T, id string) {
|
|
||||||
res := rules.Delete(base.Client, id)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted security rule %s", id)
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNetworkCRUDOperations(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
// Create a network
|
|
||||||
n, err := networks.Create(Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: networks.Up}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer networks.Delete(Client, n.ID)
|
|
||||||
th.AssertEquals(t, n.Name, "sample_network")
|
|
||||||
th.AssertEquals(t, n.AdminStateUp, true)
|
|
||||||
networkID := n.ID
|
|
||||||
|
|
||||||
// List networks
|
|
||||||
pager := networks.List(Client, networks.ListOpts{Limit: 2})
|
|
||||||
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
networkList, err := networks.ExtractNetworks(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, n := range networkList {
|
|
||||||
t.Logf("Network: ID [%s] Name [%s] Status [%s] Is shared? [%s]",
|
|
||||||
n.ID, n.Name, n.Status, strconv.FormatBool(n.Shared))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
|
|
||||||
// Get a network
|
|
||||||
if networkID == "" {
|
|
||||||
t.Fatalf("In order to retrieve a network, the NetworkID must be set")
|
|
||||||
}
|
|
||||||
n, err = networks.Get(Client, networkID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, n.Status, "ACTIVE")
|
|
||||||
th.AssertDeepEquals(t, n.Subnets, []string{})
|
|
||||||
th.AssertEquals(t, n.Name, "sample_network")
|
|
||||||
th.AssertEquals(t, n.AdminStateUp, true)
|
|
||||||
th.AssertEquals(t, n.Shared, false)
|
|
||||||
th.AssertEquals(t, n.ID, networkID)
|
|
||||||
|
|
||||||
// Update network
|
|
||||||
n, err = networks.Update(Client, networkID, networks.UpdateOpts{Name: "new_network_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, n.Name, "new_network_name")
|
|
||||||
|
|
||||||
// Delete network
|
|
||||||
res := networks.Delete(Client, networkID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateMultipleNetworks(t *testing.T) {
|
|
||||||
//networks.CreateMany()
|
|
||||||
}
|
|
117
vendor/github.com/rackspace/gophercloud/acceptance/openstack/networking/v2/port_test.go
generated
vendored
117
vendor/github.com/rackspace/gophercloud/acceptance/openstack/networking/v2/port_test.go
generated
vendored
|
@ -1,117 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPortCRUD(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
// Setup network
|
|
||||||
t.Log("Setting up network")
|
|
||||||
networkID, err := createNetwork()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer networks.Delete(Client, networkID)
|
|
||||||
|
|
||||||
// Setup subnet
|
|
||||||
t.Logf("Setting up subnet on network %s", networkID)
|
|
||||||
subnetID, err := createSubnet(networkID)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
defer subnets.Delete(Client, subnetID)
|
|
||||||
|
|
||||||
// Create port
|
|
||||||
t.Logf("Create port based on subnet %s", subnetID)
|
|
||||||
portID := createPort(t, networkID, subnetID)
|
|
||||||
|
|
||||||
// List ports
|
|
||||||
t.Logf("Listing all ports")
|
|
||||||
listPorts(t)
|
|
||||||
|
|
||||||
// Get port
|
|
||||||
if portID == "" {
|
|
||||||
t.Fatalf("In order to retrieve a port, the portID must be set")
|
|
||||||
}
|
|
||||||
p, err := ports.Get(Client, portID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, p.ID, portID)
|
|
||||||
|
|
||||||
// Update port
|
|
||||||
p, err = ports.Update(Client, portID, ports.UpdateOpts{Name: "new_port_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, p.Name, "new_port_name")
|
|
||||||
|
|
||||||
// Delete port
|
|
||||||
res := ports.Delete(Client, portID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPort(t *testing.T, networkID, subnetID string) string {
|
|
||||||
enable := false
|
|
||||||
opts := ports.CreateOpts{
|
|
||||||
NetworkID: networkID,
|
|
||||||
Name: "my_port",
|
|
||||||
AdminStateUp: &enable,
|
|
||||||
FixedIPs: []ports.IP{ports.IP{SubnetID: subnetID}},
|
|
||||||
}
|
|
||||||
p, err := ports.Create(Client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, p.NetworkID, networkID)
|
|
||||||
th.AssertEquals(t, p.Name, "my_port")
|
|
||||||
th.AssertEquals(t, p.AdminStateUp, false)
|
|
||||||
|
|
||||||
return p.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func listPorts(t *testing.T) {
|
|
||||||
count := 0
|
|
||||||
pager := ports.List(Client, ports.ListOpts{})
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
count++
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
portList, err := ports.ExtractPorts(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, p := range portList {
|
|
||||||
t.Logf("Port: ID [%s] Name [%s] Status [%s] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
|
|
||||||
p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
t.Logf("No pages were iterated over when listing ports")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNetwork() (string, error) {
|
|
||||||
res, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: networks.Up}).Extract()
|
|
||||||
return res.ID, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSubnet(networkID string) (string, error) {
|
|
||||||
s, err := subnets.Create(Client, subnets.CreateOpts{
|
|
||||||
NetworkID: networkID,
|
|
||||||
CIDR: "192.168.199.0/24",
|
|
||||||
IPVersion: subnets.IPv4,
|
|
||||||
Name: "my_subnet",
|
|
||||||
EnableDHCP: subnets.Down,
|
|
||||||
}).Extract()
|
|
||||||
return s.ID, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPortBatchCreate(t *testing.T) {
|
|
||||||
// todo
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
// +build acceptance networking
|
|
||||||
|
|
||||||
package v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestList(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
pager := subnets.List(Client, subnets.ListOpts{Limit: 2})
|
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
t.Logf("--- Page ---")
|
|
||||||
|
|
||||||
subnetList, err := subnets.ExtractSubnets(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, s := range subnetList {
|
|
||||||
t.Logf("Subnet: ID [%s] Name [%s] IP Version [%d] CIDR [%s] GatewayIP [%s]",
|
|
||||||
s.ID, s.Name, s.IPVersion, s.CIDR, s.GatewayIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCRUD(t *testing.T) {
|
|
||||||
Setup(t)
|
|
||||||
defer Teardown()
|
|
||||||
|
|
||||||
// Setup network
|
|
||||||
t.Log("Setting up network")
|
|
||||||
n, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: networks.Up}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
networkID := n.ID
|
|
||||||
defer networks.Delete(Client, networkID)
|
|
||||||
|
|
||||||
// Create subnet
|
|
||||||
t.Log("Create subnet")
|
|
||||||
enable := false
|
|
||||||
opts := subnets.CreateOpts{
|
|
||||||
NetworkID: networkID,
|
|
||||||
CIDR: "192.168.199.0/24",
|
|
||||||
IPVersion: subnets.IPv4,
|
|
||||||
Name: "my_subnet",
|
|
||||||
EnableDHCP: &enable,
|
|
||||||
}
|
|
||||||
s, err := subnets.Create(Client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
th.AssertEquals(t, s.NetworkID, networkID)
|
|
||||||
th.AssertEquals(t, s.CIDR, "192.168.199.0/24")
|
|
||||||
th.AssertEquals(t, s.IPVersion, 4)
|
|
||||||
th.AssertEquals(t, s.Name, "my_subnet")
|
|
||||||
th.AssertEquals(t, s.EnableDHCP, false)
|
|
||||||
subnetID := s.ID
|
|
||||||
|
|
||||||
// Get subnet
|
|
||||||
t.Log("Getting subnet")
|
|
||||||
s, err = subnets.Get(Client, subnetID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, s.ID, subnetID)
|
|
||||||
|
|
||||||
// Update subnet
|
|
||||||
t.Log("Update subnet")
|
|
||||||
s, err = subnets.Update(Client, subnetID, subnets.UpdateOpts{Name: "new_subnet_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, s.Name, "new_subnet_name")
|
|
||||||
|
|
||||||
// Delete subnet
|
|
||||||
t.Log("Delete subnet")
|
|
||||||
res := subnets.Delete(Client, subnetID)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBatchCreate(t *testing.T) {
|
|
||||||
// todo
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAccounts(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
// Update an account's metadata.
|
|
||||||
updateres := accounts.Update(client, accounts.UpdateOpts{Metadata: metadata})
|
|
||||||
t.Logf("Update Account Response: %+v\n", updateres)
|
|
||||||
updateHeaders, err := updateres.Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Update Account Response Headers: %+v\n", updateHeaders)
|
|
||||||
|
|
||||||
// Defer the deletion of the metadata set above.
|
|
||||||
defer func() {
|
|
||||||
tempMap := make(map[string]string)
|
|
||||||
for k := range metadata {
|
|
||||||
tempMap[k] = ""
|
|
||||||
}
|
|
||||||
updateres = accounts.Update(client, accounts.UpdateOpts{Metadata: tempMap})
|
|
||||||
th.AssertNoErr(t, updateres.Err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Extract the custom metadata from the 'Get' response.
|
|
||||||
res := accounts.Get(client, nil)
|
|
||||||
|
|
||||||
h, err := res.Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Get Account Response Headers: %+v\n", h)
|
|
||||||
|
|
||||||
am, err := res.ExtractMetadata()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for k := range metadata {
|
|
||||||
if am[k] != metadata[strings.Title(k)] {
|
|
||||||
t.Errorf("Expected custom metadata with key: %s", k)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
// numContainers is the number of containers to create for testing.
|
|
||||||
var numContainers = 2
|
|
||||||
|
|
||||||
func TestContainers(t *testing.T) {
|
|
||||||
// Create a new client to execute the HTTP requests. See common.go for newClient body.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
// Create a slice of random container names.
|
|
||||||
cNames := make([]string, numContainers)
|
|
||||||
for i := 0; i < numContainers; i++ {
|
|
||||||
cNames[i] = tools.RandomString("gophercloud-test-container-", 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create numContainers containers.
|
|
||||||
for i := 0; i < len(cNames); i++ {
|
|
||||||
res := containers.Create(client, cNames[i], nil)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
// Delete the numContainers containers after function completion.
|
|
||||||
defer func() {
|
|
||||||
for i := 0; i < len(cNames); i++ {
|
|
||||||
res := containers.Delete(client, cNames[i])
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// List the numContainer names that were just created. To just list those,
|
|
||||||
// the 'prefix' parameter is used.
|
|
||||||
err := containers.List(client, &containers.ListOpts{Full: true, Prefix: "gophercloud-test-container-"}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
containerList, err := containers.ExtractInfo(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, n := range containerList {
|
|
||||||
t.Logf("Container: Name [%s] Count [%d] Bytes [%d]",
|
|
||||||
n.Name, n.Count, n.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// List the info for the numContainer containers that were created.
|
|
||||||
err = containers.List(client, &containers.ListOpts{Full: false, Prefix: "gophercloud-test-container-"}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
containerList, err := containers.ExtractNames(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for _, n := range containerList {
|
|
||||||
t.Logf("Container: Name [%s]", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// Update one of the numContainer container metadata.
|
|
||||||
updateres := containers.Update(client, cNames[0], &containers.UpdateOpts{Metadata: metadata})
|
|
||||||
th.AssertNoErr(t, updateres.Err)
|
|
||||||
// After the tests are done, delete the metadata that was set.
|
|
||||||
defer func() {
|
|
||||||
tempMap := make(map[string]string)
|
|
||||||
for k := range metadata {
|
|
||||||
tempMap[k] = ""
|
|
||||||
}
|
|
||||||
res := containers.Update(client, cNames[0], &containers.UpdateOpts{Metadata: tempMap})
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Retrieve a container's metadata.
|
|
||||||
cm, err := containers.Get(client, cNames[0]).ExtractMetadata()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for k := range metadata {
|
|
||||||
if cm[k] != metadata[strings.Title(k)] {
|
|
||||||
t.Errorf("Expected custom metadata with key: %s", k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListAllContainers(t *testing.T) {
|
|
||||||
// Create a new client to execute the HTTP requests. See common.go for newClient body.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
numContainers := 20
|
|
||||||
|
|
||||||
// Create a slice of random container names.
|
|
||||||
cNames := make([]string, numContainers)
|
|
||||||
for i := 0; i < numContainers; i++ {
|
|
||||||
cNames[i] = tools.RandomString("gophercloud-test-container-", 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create numContainers containers.
|
|
||||||
for i := 0; i < len(cNames); i++ {
|
|
||||||
res := containers.Create(client, cNames[i], nil)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
// Delete the numContainers containers after function completion.
|
|
||||||
defer func() {
|
|
||||||
for i := 0; i < len(cNames); i++ {
|
|
||||||
res := containers.Delete(client, cNames[i])
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// List all the numContainer names that were just created. To just list those,
|
|
||||||
// the 'prefix' parameter is used.
|
|
||||||
allPages, err := containers.List(client, &containers.ListOpts{Full: true, Limit: 5, Prefix: "gophercloud-test-container-"}).AllPages()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
containerInfoList, err := containers.ExtractInfo(allPages)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for _, n := range containerInfoList {
|
|
||||||
t.Logf("Container: Name [%s] Count [%d] Bytes [%d]",
|
|
||||||
n.Name, n.Count, n.Bytes)
|
|
||||||
}
|
|
||||||
th.AssertEquals(t, numContainers, len(containerInfoList))
|
|
||||||
|
|
||||||
// List the info for all the numContainer containers that were created.
|
|
||||||
allPages, err = containers.List(client, &containers.ListOpts{Full: false, Limit: 2, Prefix: "gophercloud-test-container-"}).AllPages()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
containerNamesList, err := containers.ExtractNames(allPages)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for _, n := range containerNamesList {
|
|
||||||
t.Logf("Container: Name [%s]", n)
|
|
||||||
}
|
|
||||||
th.AssertEquals(t, numContainers, len(containerNamesList))
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
// numObjects is the number of objects to create for testing.
|
|
||||||
var numObjects = 2
|
|
||||||
|
|
||||||
func TestObjects(t *testing.T) {
|
|
||||||
// Create a provider client for executing the HTTP request.
|
|
||||||
// See common.go for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
// Make a slice of length numObjects to hold the random object names.
|
|
||||||
oNames := make([]string, numObjects)
|
|
||||||
for i := 0; i < len(oNames); i++ {
|
|
||||||
oNames[i] = tools.RandomString("test-object-", 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a container to hold the test objects.
|
|
||||||
cName := tools.RandomString("test-container-", 8)
|
|
||||||
header, err := containers.Create(client, cName, nil).ExtractHeader()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Create object headers: %+v\n", header)
|
|
||||||
|
|
||||||
// Defer deletion of the container until after testing.
|
|
||||||
defer func() {
|
|
||||||
res := containers.Delete(client, cName)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Create a slice of buffers to hold the test object content.
|
|
||||||
oContents := make([]*bytes.Buffer, numObjects)
|
|
||||||
for i := 0; i < numObjects; i++ {
|
|
||||||
oContents[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
|
|
||||||
res := objects.Create(client, cName, oNames[i], oContents[i], nil)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
// Delete the objects after testing.
|
|
||||||
defer func() {
|
|
||||||
for i := 0; i < numObjects; i++ {
|
|
||||||
res := objects.Delete(client, cName, oNames[i], nil)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
ons := make([]string, 0, len(oNames))
|
|
||||||
err = objects.List(client, cName, &objects.ListOpts{Full: false, Prefix: "test-object-"}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
names, err := objects.ExtractNames(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
ons = append(ons, names...)
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, len(ons), len(oNames))
|
|
||||||
|
|
||||||
ois := make([]objects.Object, 0, len(oNames))
|
|
||||||
err = objects.List(client, cName, &objects.ListOpts{Full: true, Prefix: "test-object-"}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
info, err := objects.ExtractInfo(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
ois = append(ois, info...)
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
th.AssertEquals(t, len(ois), len(oNames))
|
|
||||||
|
|
||||||
// Copy the contents of one object to another.
|
|
||||||
copyres := objects.Copy(client, cName, oNames[0], &objects.CopyOpts{Destination: cName + "/" + oNames[1]})
|
|
||||||
th.AssertNoErr(t, copyres.Err)
|
|
||||||
|
|
||||||
// Download one of the objects that was created above.
|
|
||||||
o1Content, err := objects.Download(client, cName, oNames[0], nil).ExtractContent()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// Download the another object that was create above.
|
|
||||||
o2Content, err := objects.Download(client, cName, oNames[1], nil).ExtractContent()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
// Compare the two object's contents to test that the copy worked.
|
|
||||||
th.AssertEquals(t, string(o2Content), string(o1Content))
|
|
||||||
|
|
||||||
// Update an object's metadata.
|
|
||||||
updateres := objects.Update(client, cName, oNames[0], &objects.UpdateOpts{Metadata: metadata})
|
|
||||||
th.AssertNoErr(t, updateres.Err)
|
|
||||||
|
|
||||||
// Delete the object's metadata after testing.
|
|
||||||
defer func() {
|
|
||||||
tempMap := make(map[string]string)
|
|
||||||
for k := range metadata {
|
|
||||||
tempMap[k] = ""
|
|
||||||
}
|
|
||||||
res := objects.Update(client, cName, oNames[0], &objects.UpdateOpts{Metadata: tempMap})
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Retrieve an object's metadata.
|
|
||||||
om, err := objects.Get(client, cName, oNames[0], nil).ExtractMetadata()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
for k := range metadata {
|
|
||||||
if om[k] != metadata[strings.Title(k)] {
|
|
||||||
t.Errorf("Expected custom metadata with key: %s", k)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/buildinfo"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBuildInfo(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
bi, err := buildinfo.Get(client).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("retrieved build info: %+v\n", bi)
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stackevents"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stacks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStackEvents(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
stackName := "postman_stack_2"
|
|
||||||
resourceName := "hello_world"
|
|
||||||
var eventID string
|
|
||||||
|
|
||||||
createOpts := stacks.CreateOpts{
|
|
||||||
Name: stackName,
|
|
||||||
Template: template,
|
|
||||||
Timeout: 5,
|
|
||||||
}
|
|
||||||
stack, err := stacks.Create(client, createOpts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created stack: %+v\n", stack)
|
|
||||||
defer func() {
|
|
||||||
err := stacks.Delete(client, stackName, stack.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Deleted stack (%s)", stackName)
|
|
||||||
}()
|
|
||||||
err = gophercloud.WaitFor(60, func() (bool, error) {
|
|
||||||
getStack, err := stacks.Get(client, stackName, stack.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if getStack.Status == "CREATE_COMPLETE" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
err = stackevents.List(client, stackName, stack.ID, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
events, err := stackevents.ExtractEvents(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("listed events: %+v\n", events)
|
|
||||||
eventID = events[0].ID
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
err = stackevents.ListResourceEvents(client, stackName, stack.ID, resourceName, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
resourceEvents, err := stackevents.ExtractEvents(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("listed resource events: %+v\n", resourceEvents)
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
event, err := stackevents.Get(client, stackName, stack.ID, resourceName, eventID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("retrieved event: %+v\n", event)
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stackresources"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stacks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStackResources(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
stackName := "postman_stack_2"
|
|
||||||
|
|
||||||
createOpts := stacks.CreateOpts{
|
|
||||||
Name: stackName,
|
|
||||||
Template: template,
|
|
||||||
Timeout: 5,
|
|
||||||
}
|
|
||||||
stack, err := stacks.Create(client, createOpts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created stack: %+v\n", stack)
|
|
||||||
defer func() {
|
|
||||||
err := stacks.Delete(client, stackName, stack.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Deleted stack (%s)", stackName)
|
|
||||||
}()
|
|
||||||
err = gophercloud.WaitFor(60, func() (bool, error) {
|
|
||||||
getStack, err := stacks.Get(client, stackName, stack.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if getStack.Status == "CREATE_COMPLETE" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
resourceName := "hello_world"
|
|
||||||
resource, err := stackresources.Get(client, stackName, stack.ID, resourceName).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Got stack resource: %+v\n", resource)
|
|
||||||
|
|
||||||
metadata, err := stackresources.Metadata(client, stackName, stack.ID, resourceName).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Got stack resource metadata: %+v\n", metadata)
|
|
||||||
|
|
||||||
err = stackresources.List(client, stackName, stack.ID, stackresources.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
resources, err := stackresources.ExtractResources(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("resources: %+v\n", resources)
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stacks"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStacks(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
stackName1 := "gophercloud-test-stack-2"
|
|
||||||
createOpts := stacks.CreateOpts{
|
|
||||||
Name: stackName1,
|
|
||||||
Template: template,
|
|
||||||
Timeout: 5,
|
|
||||||
}
|
|
||||||
stack, err := stacks.Create(client, createOpts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created stack: %+v\n", stack)
|
|
||||||
defer func() {
|
|
||||||
err := stacks.Delete(client, stackName1, stack.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Deleted stack (%s)", stackName1)
|
|
||||||
}()
|
|
||||||
err = gophercloud.WaitFor(60, func() (bool, error) {
|
|
||||||
getStack, err := stacks.Get(client, stackName1, stack.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if getStack.Status == "CREATE_COMPLETE" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
updateOpts := stacks.UpdateOpts{
|
|
||||||
Template: template,
|
|
||||||
Timeout: 20,
|
|
||||||
}
|
|
||||||
err = stacks.Update(client, stackName1, stack.ID, updateOpts).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
err = gophercloud.WaitFor(60, func() (bool, error) {
|
|
||||||
getStack, err := stacks.Get(client, stackName1, stack.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if getStack.Status == "UPDATE_COMPLETE" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Logf("Updated stack")
|
|
||||||
|
|
||||||
err = stacks.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
stackList, err := stacks.ExtractStacks(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
t.Logf("Got stack list: %+v\n", stackList)
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
getStack, err := stacks.Get(client, stackName1, stack.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Got stack: %+v\n", getStack)
|
|
||||||
|
|
||||||
abandonedStack, err := stacks.Abandon(client, stackName1, stack.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Abandonded stack %+v\n", abandonedStack)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stacks"
|
|
||||||
"github.com/rackspace/gophercloud/openstack/orchestration/v1/stacktemplates"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStackTemplates(t *testing.T) {
|
|
||||||
// Create a provider client for making the HTTP requests.
|
|
||||||
// See common.go in this directory for more information.
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
stackName := "postman_stack_2"
|
|
||||||
|
|
||||||
createOpts := stacks.CreateOpts{
|
|
||||||
Name: stackName,
|
|
||||||
Template: template,
|
|
||||||
Timeout: 5,
|
|
||||||
}
|
|
||||||
stack, err := stacks.Create(client, createOpts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created stack: %+v\n", stack)
|
|
||||||
defer func() {
|
|
||||||
err := stacks.Delete(client, stackName, stack.ID).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Deleted stack (%s)", stackName)
|
|
||||||
}()
|
|
||||||
err = gophercloud.WaitFor(60, func() (bool, error) {
|
|
||||||
getStack, err := stacks.Get(client, stackName, stack.ID).Extract()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if getStack.Status == "CREATE_COMPLETE" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
tmpl, err := stacktemplates.Get(client, stackName, stack.ID).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("retrieved template: %+v\n", tmpl)
|
|
||||||
|
|
||||||
validateOpts := stacktemplates.ValidateOpts{
|
|
||||||
Template: map[string]interface{}{
|
|
||||||
"heat_template_version": "2013-05-23",
|
|
||||||
"description": "Simple template to test heat commands",
|
|
||||||
"parameters": map[string]interface{}{
|
|
||||||
"flavor": map[string]interface{}{
|
|
||||||
"default": "m1.tiny",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"resources": map[string]interface{}{
|
|
||||||
"hello_world": map[string]interface{}{
|
|
||||||
"type": "OS::Nova::Server",
|
|
||||||
"properties": map[string]interface{}{
|
|
||||||
"key_name": "heat_key",
|
|
||||||
"flavor": map[string]interface{}{
|
|
||||||
"get_param": "flavor",
|
|
||||||
},
|
|
||||||
"image": "ad091b52-742f-469e-8f3c-fd81cadf0743",
|
|
||||||
"user_data": "#!/bin/bash -xv\necho \"hello world\" > /root/hello-world.txt\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
validatedTemplate, err := stacktemplates.Validate(client, validateOpts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("validated template: %+v\n", validatedTemplate)
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
// +build acceptance blockstorage snapshots
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
"github.com/rackspace/gophercloud/rackspace/blockstorage/v1/snapshots"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSnapshots(t *testing.T) {
|
|
||||||
client := setup(t)
|
|
||||||
volID := testVolumeCreate(t, client)
|
|
||||||
|
|
||||||
t.Log("Creating snapshots")
|
|
||||||
s := testSnapshotCreate(t, client, volID)
|
|
||||||
id := s.ID
|
|
||||||
|
|
||||||
t.Log("Listing snapshots")
|
|
||||||
testSnapshotList(t, client)
|
|
||||||
|
|
||||||
t.Logf("Getting snapshot %s", id)
|
|
||||||
testSnapshotGet(t, client, id)
|
|
||||||
|
|
||||||
t.Logf("Updating snapshot %s", id)
|
|
||||||
testSnapshotUpdate(t, client, id)
|
|
||||||
|
|
||||||
t.Logf("Deleting snapshot %s", id)
|
|
||||||
testSnapshotDelete(t, client, id)
|
|
||||||
s.WaitUntilDeleted(client, -1)
|
|
||||||
|
|
||||||
t.Logf("Deleting volume %s", volID)
|
|
||||||
testVolumeDelete(t, client, volID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSnapshotCreate(t *testing.T, client *gophercloud.ServiceClient, volID string) *snapshots.Snapshot {
|
|
||||||
opts := snapshots.CreateOpts{VolumeID: volID, Name: "snapshot-001"}
|
|
||||||
s, err := snapshots.Create(client, opts).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created snapshot %s", s.ID)
|
|
||||||
|
|
||||||
t.Logf("Waiting for new snapshot to become available...")
|
|
||||||
start := time.Now().Second()
|
|
||||||
s.WaitUntilComplete(client, -1)
|
|
||||||
t.Logf("Snapshot completed after %ds", time.Now().Second()-start)
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSnapshotList(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
snapshots.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
sList, err := snapshots.ExtractSnapshots(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, s := range sList {
|
|
||||||
t.Logf("Snapshot: ID [%s] Name [%s] Volume ID [%s] Progress [%s] Created [%s]",
|
|
||||||
s.ID, s.Name, s.VolumeID, s.Progress, s.CreatedAt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSnapshotGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
_, err := snapshots.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSnapshotUpdate(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
_, err := snapshots.Update(client, id, snapshots.UpdateOpts{Name: "new_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSnapshotDelete(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
res := snapshots.Delete(client, id)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted snapshot %s", id)
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
// +build acceptance blockstorage volumes
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
os "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
"github.com/rackspace/gophercloud/rackspace/blockstorage/v1/volumes"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVolumes(t *testing.T) {
|
|
||||||
client := setup(t)
|
|
||||||
|
|
||||||
t.Logf("Listing volumes")
|
|
||||||
testVolumeList(t, client)
|
|
||||||
|
|
||||||
t.Logf("Creating volume")
|
|
||||||
volumeID := testVolumeCreate(t, client)
|
|
||||||
|
|
||||||
t.Logf("Getting volume %s", volumeID)
|
|
||||||
testVolumeGet(t, client, volumeID)
|
|
||||||
|
|
||||||
t.Logf("Updating volume %s", volumeID)
|
|
||||||
testVolumeUpdate(t, client, volumeID)
|
|
||||||
|
|
||||||
t.Logf("Deleting volume %s", volumeID)
|
|
||||||
testVolumeDelete(t, client, volumeID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVolumeList(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
volumes.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
vList, err := volumes.ExtractVolumes(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, v := range vList {
|
|
||||||
t.Logf("Volume: ID [%s] Name [%s] Type [%s] Created [%s]", v.ID, v.Name,
|
|
||||||
v.VolumeType, v.CreatedAt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVolumeCreate(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
vol, err := volumes.Create(client, os.CreateOpts{Size: 75}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created volume: ID [%s] Size [%s]", vol.ID, vol.Size)
|
|
||||||
return vol.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVolumeGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
vol, err := volumes.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created volume: ID [%s] Size [%s]", vol.ID, vol.Size)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVolumeUpdate(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
vol, err := volumes.Update(client, id, volumes.UpdateOpts{Name: "new_name"}).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Created volume: ID [%s] Name [%s]", vol.ID, vol.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVolumeDelete(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
res := volumes.Delete(client, id)
|
|
||||||
th.AssertNoErr(t, res.Err)
|
|
||||||
t.Logf("Deleted volume %s", id)
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// +build acceptance blockstorage volumetypes
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
"github.com/rackspace/gophercloud/rackspace/blockstorage/v1/volumetypes"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
|
||||||
client := setup(t)
|
|
||||||
|
|
||||||
t.Logf("Listing volume types")
|
|
||||||
id := testList(t, client)
|
|
||||||
|
|
||||||
t.Logf("Getting volume type %s", id)
|
|
||||||
testGet(t, client, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testList(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
var lastID string
|
|
||||||
|
|
||||||
volumetypes.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
typeList, err := volumetypes.ExtractVolumeTypes(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, vt := range typeList {
|
|
||||||
t.Logf("Volume type: ID [%s] Name [%s]", vt.ID, vt.Name)
|
|
||||||
lastID = vt.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return lastID
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
vt, err := volumetypes.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Volume: ID [%s] Name [%s]", vt.ID, vt.Name)
|
|
||||||
}
|
|
32
vendor/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/base_test.go
generated
vendored
32
vendor/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/base_test.go
generated
vendored
|
@ -1,32 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
"github.com/rackspace/gophercloud/rackspace/cdn/v1/base"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBaseOps(t *testing.T) {
|
|
||||||
client := newClient(t)
|
|
||||||
t.Log("Retrieving Home Document")
|
|
||||||
testHomeDocumentGet(t, client)
|
|
||||||
|
|
||||||
t.Log("Pinging root URL")
|
|
||||||
testPing(t, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHomeDocumentGet(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
hd, err := base.Get(client).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Retrieved home document: %+v", *hd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPing(t *testing.T, client *gophercloud.ServiceClient) {
|
|
||||||
err := base.Ping(client).ExtractErr()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Successfully pinged root URL")
|
|
||||||
}
|
|
47
vendor/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/flavor_test.go
generated
vendored
47
vendor/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/flavor_test.go
generated
vendored
|
@ -1,47 +0,0 @@
|
||||||
// +build acceptance
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/rackspace/gophercloud"
|
|
||||||
os "github.com/rackspace/gophercloud/openstack/cdn/v1/flavors"
|
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
|
||||||
"github.com/rackspace/gophercloud/rackspace/cdn/v1/flavors"
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFlavor(t *testing.T) {
|
|
||||||
client := newClient(t)
|
|
||||||
|
|
||||||
t.Log("Listing Flavors")
|
|
||||||
id := testFlavorsList(t, client)
|
|
||||||
|
|
||||||
t.Log("Retrieving Flavor")
|
|
||||||
testFlavorGet(t, client, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFlavorsList(t *testing.T, client *gophercloud.ServiceClient) string {
|
|
||||||
var id string
|
|
||||||
err := flavors.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
|
||||||
flavorList, err := os.ExtractFlavors(page)
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
|
|
||||||
for _, flavor := range flavorList {
|
|
||||||
t.Logf("Listing flavor: ID [%s] Providers [%+v]", flavor.ID, flavor.Providers)
|
|
||||||
id = flavor.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFlavorGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
|
||||||
flavor, err := flavors.Get(client, id).Extract()
|
|
||||||
th.AssertNoErr(t, err)
|
|
||||||
t.Logf("Retrieved Flavor: %+v", *flavor)
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue