Update deps
This commit is contained in:
parent
af37736a38
commit
3e15a1f056
|
@ -15,63 +15,63 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/endpoints",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/endpoints",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/ec2query",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/query",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/rest",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/rest",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/restxml",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/restxml",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/internal/signer/v4",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/signer/v4",
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/ec2",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/iam",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/s3",
|
||||
"Comment": "v0.9.16-1-g66c840e",
|
||||
"Rev": "66c840e9981dd121a4239fc25e33b6c1c1caa781"
|
||||
"Comment": "v0.10.0-6-g83bae04",
|
||||
"Rev": "83bae04b770b2b9aae4c946f795149d294e147d3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
||||
"Comment": "v2.0.0-36-g2038b59",
|
||||
"Rev": "2038b5942e8e7f4f244729ff9353afab8ba11afc"
|
||||
"Comment": "v2.0.0-38-g003851b",
|
||||
"Rev": "003851be7bb0694fe3cc457a49529a19388ee7cf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/duosecurity/duo_api_golang",
|
||||
|
@ -83,18 +83,18 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-ldap/ldap",
|
||||
"Comment": "v2.1",
|
||||
"Rev": "90b1711ae8a4d6aef7576dfe0bc48def3f3ffcf4"
|
||||
"Comment": "v2.1-2-gd57f702",
|
||||
"Rev": "d57f702d9f8a22278428abed6c025621ab657fd6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
"Comment": "v1.2-119-g527bcd5",
|
||||
"Rev": "527bcd55aab2e53314f1a150922560174b493034"
|
||||
"Comment": "v1.2-121-g69e3ed7",
|
||||
"Rev": "69e3ed7607d7c139386480824801584c947c67cf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gocql/gocql",
|
||||
"Comment": "1st_gen_framing-323-g8041a37",
|
||||
"Rev": "8041a37b40f2ca115d6c2902b279250eb627d7af"
|
||||
"Comment": "1st_gen_framing-339-ga13e827",
|
||||
"Rev": "a13e827ba9f379ea13199708c1b262a5d30b95a9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/snappy",
|
||||
|
@ -102,16 +102,20 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/go-github/github",
|
||||
"Rev": "84fc80440d3bb3a82d297b827308ce11dcf047eb"
|
||||
"Rev": "81d0490d8aa8400f6760a077f4a2039eb0296e86"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/go-querystring/query",
|
||||
"Rev": "547ef5ac979778feb2f760cdb5f4eae1a2207b86"
|
||||
"Rev": "2a60fc2ba6c19de80291203597d752e9ba58e4c0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hailocab/go-hostpool",
|
||||
"Rev": "be8d763da234fdc1ffbf8c3149c308db31fbf894"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/consul/api",
|
||||
"Comment": "v0.5.2-469-g6a350d5",
|
||||
"Rev": "6a350d5d19a41f94e0c99a933410e8545c4e7a51"
|
||||
"Comment": "v0.6.0-rc1-3-g921602b",
|
||||
"Rev": "921602b565b04d59ac634d53542d05dfd93a6ca3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/errwrap",
|
||||
|
@ -131,7 +135,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
"Rev": "17e3543cc4e0b72d6c71d2e59e27a10821ea353b"
|
||||
"Rev": "a6091bb5d00e2e9c4a16a0e739e306f8a3071a3c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/hcl",
|
||||
|
@ -141,6 +145,11 @@
|
|||
"ImportPath": "github.com/hashicorp/logutils",
|
||||
"Rev": "0dc08b1671f34c4250ce212759ebd880f743d883"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/serf/coordinate",
|
||||
"Comment": "v0.6.4-141-gc952108",
|
||||
"Rev": "c9521088072459c5113a5e78e353b0b5b5ceec58"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/uuid",
|
||||
"Rev": "2951e8b9707a040acdb49145ed9f36a088f3532e"
|
||||
|
@ -164,7 +173,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/go-homedir",
|
||||
"Rev": "df55a15e5ce646808815381b3db47a8c66ea62f4"
|
||||
"Rev": "d682a8f0cf139663a984ff12528da460ca963de9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/mapstructure",
|
||||
|
@ -185,7 +194,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/ugorji/go/codec",
|
||||
"Rev": "8a2a3a8c488c3ebd98f422a965260278267a0551"
|
||||
"Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vaughan0/go-ini",
|
||||
|
@ -217,7 +226,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "2cba614e8ff920c60240d2677bc019af32ee04e5"
|
||||
"Rev": "c95266fa704a83c2716406ae957772a273e1380d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
|
|
121
Godeps/_workspace/src/github.com/armon/go-metrics/datadog/dogstatsd_test.go
generated
vendored
Normal file
121
Godeps/_workspace/src/github.com/armon/go-metrics/datadog/dogstatsd_test.go
generated
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var EmptyTags []string
|
||||
|
||||
const (
|
||||
DogStatsdAddr = "127.0.0.1:7254"
|
||||
HostnameEnabled = true
|
||||
HostnameDisabled = false
|
||||
TestHostname = "test_hostname"
|
||||
)
|
||||
|
||||
func MockGetHostname() string {
|
||||
return TestHostname
|
||||
}
|
||||
|
||||
var ParseKeyTests = []struct {
|
||||
KeyToParse []string
|
||||
Tags []string
|
||||
PropagateHostname bool
|
||||
ExpectedKey []string
|
||||
ExpectedTags []string
|
||||
}{
|
||||
{[]string{"a", MockGetHostname(), "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
|
||||
{[]string{"a", "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
|
||||
{[]string{"a", "b", "c"}, EmptyTags, HostnameEnabled, []string{"a", "b", "c"}, []string{fmt.Sprintf("host:%s", MockGetHostname())}},
|
||||
}
|
||||
|
||||
var FlattenKeyTests = []struct {
|
||||
KeyToFlatten []string
|
||||
Expected string
|
||||
}{
|
||||
{[]string{"a", "b", "c"}, "a.b.c"},
|
||||
{[]string{"spaces must", "flatten", "to", "underscores"}, "spaces_must.flatten.to.underscores"},
|
||||
}
|
||||
|
||||
var MetricSinkTests = []struct {
|
||||
Method string
|
||||
Metric []string
|
||||
Value interface{}
|
||||
Tags []string
|
||||
PropagateHostname bool
|
||||
Expected string
|
||||
}{
|
||||
{"SetGauge", []string{"foo", "bar"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar:42.000000|g"},
|
||||
{"SetGauge", []string{"foo", "bar", "baz"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar.baz:42.000000|g"},
|
||||
{"AddSample", []string{"sample", "thing"}, float32(4), EmptyTags, HostnameDisabled, "sample.thing:4.000000|ms"},
|
||||
{"IncrCounter", []string{"count", "me"}, float32(3), EmptyTags, HostnameDisabled, "count.me:3|c"},
|
||||
|
||||
{"SetGauge", []string{"foo", "baz"}, float32(42), []string{"my_tag:my_value"}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag:my_value"},
|
||||
{"SetGauge", []string{"foo", "bar"}, float32(42), []string{"my_tag:my_value", "other_tag:other_value"}, HostnameDisabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value"},
|
||||
{"SetGauge", []string{"foo", "bar"}, float32(42), []string{"my_tag:my_value", "other_tag:other_value"}, HostnameEnabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value,host:test_hostname"},
|
||||
}
|
||||
|
||||
func MockNewDogStatsdSink(addr string, tags []string, tagWithHostname bool) *DogStatsdSink {
|
||||
dog, _ := NewDogStatsdSink(addr, MockGetHostname())
|
||||
dog.SetTags(tags)
|
||||
if tagWithHostname {
|
||||
dog.EnableHostNamePropagation()
|
||||
}
|
||||
|
||||
return dog
|
||||
}
|
||||
|
||||
func TestParseKey(t *testing.T) {
|
||||
for _, tt := range ParseKeyTests {
|
||||
dog := MockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
|
||||
key, tags := dog.parseKey(tt.KeyToParse)
|
||||
|
||||
if !reflect.DeepEqual(key, tt.ExpectedKey) {
|
||||
t.Fatalf("Key Parsing failed for %v", tt.KeyToParse)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tags, tt.ExpectedTags) {
|
||||
t.Fatalf("Tag Parsing Failed for %v", tt.KeyToParse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenKey(t *testing.T) {
|
||||
dog := MockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)
|
||||
for _, tt := range FlattenKeyTests {
|
||||
if !reflect.DeepEqual(dog.flattenKey(tt.KeyToFlatten), tt.Expected) {
|
||||
t.Fatalf("Flattening %v failed", tt.KeyToFlatten)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetricSink(t *testing.T) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", DogStatsdAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
for _, tt := range MetricSinkTests {
|
||||
dog := MockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
|
||||
method := reflect.ValueOf(dog).MethodByName(tt.Method)
|
||||
method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Metric),
|
||||
reflect.ValueOf(tt.Value)})
|
||||
|
||||
n, _ := server.Read(buf)
|
||||
msg := buf[:n]
|
||||
if string(msg) != tt.Expected {
|
||||
t.Fatalf("Line %s does not match expected: %s", string(msg), tt.Expected)
|
||||
}
|
||||
}
|
||||
}
|
46
Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go
generated
vendored
Normal file
46
Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInmemSignal(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
|
||||
sig := NewInmemSignal(inm, syscall.SIGUSR1, buf)
|
||||
defer sig.Stop()
|
||||
|
||||
inm.SetGauge([]string{"foo"}, 42)
|
||||
inm.EmitKey([]string{"bar"}, 42)
|
||||
inm.IncrCounter([]string{"baz"}, 42)
|
||||
inm.AddSample([]string{"wow"}, 42)
|
||||
|
||||
// Wait for period to end
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
|
||||
// Send signal!
|
||||
syscall.Kill(os.Getpid(), syscall.SIGUSR1)
|
||||
|
||||
// Wait for flush
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// Check the output
|
||||
out := string(buf.Bytes())
|
||||
if !strings.Contains(out, "[G] 'foo': 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[P] 'bar': 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[C] 'baz': Count: 1 Sum: 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
if !strings.Contains(out, "[S] 'wow': Count: 1 Sum: 42") {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInmemSink(t *testing.T) {
|
||||
inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
|
||||
|
||||
data := inm.Data()
|
||||
if len(data) != 1 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
|
||||
// Add data points
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
inm.EmitKey([]string{"foo", "bar"}, 42)
|
||||
inm.IncrCounter([]string{"foo", "bar"}, 20)
|
||||
inm.IncrCounter([]string{"foo", "bar"}, 22)
|
||||
inm.AddSample([]string{"foo", "bar"}, 20)
|
||||
inm.AddSample([]string{"foo", "bar"}, 22)
|
||||
|
||||
data = inm.Data()
|
||||
if len(data) != 1 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
|
||||
intvM := data[0]
|
||||
intvM.RLock()
|
||||
|
||||
if time.Now().Sub(intvM.Interval) > 10*time.Millisecond {
|
||||
t.Fatalf("interval too old")
|
||||
}
|
||||
if intvM.Gauges["foo.bar"] != 42 {
|
||||
t.Fatalf("bad val: %v", intvM.Gauges)
|
||||
}
|
||||
if intvM.Points["foo.bar"][0] != 42 {
|
||||
t.Fatalf("bad val: %v", intvM.Points)
|
||||
}
|
||||
|
||||
agg := intvM.Counters["foo.bar"]
|
||||
if agg.Count != 2 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Sum != 42 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.SumSq != 884 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Min != 20 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Max != 22 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Mean() != 21 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Stddev() != math.Sqrt(2) {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
|
||||
if agg.LastUpdated.IsZero() {
|
||||
t.Fatalf("agg.LastUpdated is not set: %v", agg)
|
||||
}
|
||||
|
||||
diff := time.Now().Sub(agg.LastUpdated).Seconds()
|
||||
if diff > 1 {
|
||||
t.Fatalf("time diff too great: %f", diff)
|
||||
}
|
||||
|
||||
if agg = intvM.Samples["foo.bar"]; agg == nil {
|
||||
t.Fatalf("missing sample")
|
||||
}
|
||||
|
||||
intvM.RUnlock()
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
data = inm.Data()
|
||||
if len(data) != min(i+1, 5) {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
}
|
||||
|
||||
// Should not exceed 5 intervals!
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
inm.SetGauge([]string{"foo", "bar"}, 42)
|
||||
data = inm.Data()
|
||||
if len(data) != 5 {
|
||||
t.Fatalf("bad: %v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
262
Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go
generated
vendored
Normal file
262
Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go
generated
vendored
Normal file
|
@ -0,0 +1,262 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mockMetric() (*MockSink, *Metrics) {
|
||||
m := &MockSink{}
|
||||
met := &Metrics{sink: m}
|
||||
return m, met
|
||||
}
|
||||
|
||||
func TestMetrics_SetGauge(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.HostName = "test"
|
||||
met.EnableHostname = true
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "test" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "gauge" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.SetGauge([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_EmitKey(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "kv" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.EmitKey([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_IncrCounter(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "counter" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.IncrCounter([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_AddSample(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.EnableTypePrefix = true
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "sample" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.ServiceName = "service"
|
||||
met.AddSample([]string{"key"}, float32(1))
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] != 1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_MeasureSince(t *testing.T) {
|
||||
m, met := mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
n := time.Now()
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
met.EnableTypePrefix = true
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "timer" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
|
||||
m, met = mockMetric()
|
||||
met.TimerGranularity = time.Millisecond
|
||||
met.ServiceName = "service"
|
||||
met.MeasureSince([]string{"key"}, n)
|
||||
if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
|
||||
t.Fatalf("")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_EmitRuntimeStats(t *testing.T) {
|
||||
runtime.GC()
|
||||
m, met := mockMetric()
|
||||
met.emitRuntimeStats()
|
||||
|
||||
if m.keys[0][0] != "runtime" || m.keys[0][1] != "num_goroutines" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[0] <= 1 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[1][0] != "runtime" || m.keys[1][1] != "alloc_bytes" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[1] <= 40000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[2][0] != "runtime" || m.keys[2][1] != "sys_bytes" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[2] <= 100000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[3][0] != "runtime" || m.keys[3][1] != "malloc_count" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[3] <= 100 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[4][0] != "runtime" || m.keys[4][1] != "free_count" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[4] <= 100 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[5][0] != "runtime" || m.keys[5][1] != "heap_objects" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[5] <= 100 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[6][0] != "runtime" || m.keys[6][1] != "total_gc_pause_ns" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[6] <= 100000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[7][0] != "runtime" || m.keys[7][1] != "total_gc_runs" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[7] <= 1 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
|
||||
if m.keys[8][0] != "runtime" || m.keys[8][1] != "gc_pause_ns" {
|
||||
t.Fatalf("bad key %v", m.keys)
|
||||
}
|
||||
if m.vals[8] <= 1000 {
|
||||
t.Fatalf("bad val: %v", m.vals)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
k := []string{"hi", "bob"}
|
||||
exp := []string{"hi", "there", "bob"}
|
||||
out := insert(1, "there", k)
|
||||
if !reflect.DeepEqual(exp, out) {
|
||||
t.Fatalf("bad insert %v %v", exp, out)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MockSink struct {
|
||||
keys [][]string
|
||||
vals []float32
|
||||
}
|
||||
|
||||
func (m *MockSink) SetGauge(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) EmitKey(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) IncrCounter(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
func (m *MockSink) AddSample(key []string, val float32) {
|
||||
m.keys = append(m.keys, key)
|
||||
m.vals = append(m.vals, val)
|
||||
}
|
||||
|
||||
func TestFanoutSink_Gauge(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.SetGauge(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Key(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.EmitKey(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Counter(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.IncrCounter(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanoutSink_Sample(t *testing.T) {
|
||||
m1 := &MockSink{}
|
||||
m2 := &MockSink{}
|
||||
fh := &FanoutSink{m1, m2}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
fh.AddSample(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m1.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m1.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m2.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDefaultConfig(t *testing.T) {
|
||||
conf := DefaultConfig("service")
|
||||
if conf.ServiceName != "service" {
|
||||
t.Fatalf("Bad name")
|
||||
}
|
||||
if conf.HostName == "" {
|
||||
t.Fatalf("missing hostname")
|
||||
}
|
||||
if !conf.EnableHostname || !conf.EnableRuntimeMetrics {
|
||||
t.Fatalf("expect true")
|
||||
}
|
||||
if conf.EnableTypePrefix {
|
||||
t.Fatalf("expect false")
|
||||
}
|
||||
if conf.TimerGranularity != time.Millisecond {
|
||||
t.Fatalf("bad granularity")
|
||||
}
|
||||
if conf.ProfileInterval != time.Second {
|
||||
t.Fatalf("bad interval")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_SetGauge(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
SetGauge(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_EmitKey(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
EmitKey(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_IncrCounter(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
IncrCounter(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_AddSample(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
|
||||
k := []string{"test"}
|
||||
v := float32(42.0)
|
||||
AddSample(k, v)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if !reflect.DeepEqual(m.vals[0], v) {
|
||||
t.Fatalf("val not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GlobalMetrics_MeasureSince(t *testing.T) {
|
||||
m := &MockSink{}
|
||||
globalMetrics = &Metrics{sink: m}
|
||||
globalMetrics.TimerGranularity = time.Millisecond
|
||||
|
||||
k := []string{"test"}
|
||||
now := time.Now()
|
||||
MeasureSince(k, now)
|
||||
|
||||
if !reflect.DeepEqual(m.keys[0], k) {
|
||||
t.Fatalf("key not equal")
|
||||
}
|
||||
if m.vals[0] > 0.1 {
|
||||
t.Fatalf("val too large %v", m.vals[0])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStatsd_Flatten(t *testing.T) {
|
||||
s := &StatsdSink{}
|
||||
flat := s.flattenKey([]string{"a", "b", "c", "d"})
|
||||
if flat != "a.b.c.d" {
|
||||
t.Fatalf("Bad flat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsd_PushFullQueue(t *testing.T) {
|
||||
q := make(chan string, 1)
|
||||
q <- "full"
|
||||
|
||||
s := &StatsdSink{metricQueue: q}
|
||||
s.pushMetric("omit")
|
||||
|
||||
out := <-q
|
||||
if out != "full" {
|
||||
t.Fatalf("bad val %v", out)
|
||||
}
|
||||
|
||||
select {
|
||||
case v := <-q:
|
||||
t.Fatalf("bad val %v", v)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsd_Conn(t *testing.T) {
|
||||
addr := "127.0.0.1:7524"
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
list, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 7524})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer list.Close()
|
||||
buf := make([]byte, 1500)
|
||||
n, err := list.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf = buf[:n]
|
||||
reader := bufio.NewReader(bytes.NewReader(buf))
|
||||
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "gauge.val:1.000000|g\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "key.other:2.000000|kv\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "counter.me:3.000000|c\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "sample.slow_thingy:4.000000|ms\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
done <- true
|
||||
}()
|
||||
s, err := NewStatsdSink(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("bad error")
|
||||
}
|
||||
|
||||
s.SetGauge([]string{"gauge", "val"}, float32(1))
|
||||
s.EmitKey([]string{"key", "other"}, float32(2))
|
||||
s.IncrCounter([]string{"counter", "me"}, float32(3))
|
||||
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
s.Shutdown()
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("timeout")
|
||||
}
|
||||
}
|
101
Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go
generated
vendored
Normal file
101
Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func acceptConn(addr string) net.Conn {
|
||||
ln, _ := net.Listen("tcp", addr)
|
||||
conn, _ := ln.Accept()
|
||||
return conn
|
||||
}
|
||||
|
||||
func TestStatsite_Flatten(t *testing.T) {
|
||||
s := &StatsiteSink{}
|
||||
flat := s.flattenKey([]string{"a", "b", "c", "d"})
|
||||
if flat != "a.b.c.d" {
|
||||
t.Fatalf("Bad flat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsite_PushFullQueue(t *testing.T) {
|
||||
q := make(chan string, 1)
|
||||
q <- "full"
|
||||
|
||||
s := &StatsiteSink{metricQueue: q}
|
||||
s.pushMetric("omit")
|
||||
|
||||
out := <-q
|
||||
if out != "full" {
|
||||
t.Fatalf("bad val %v", out)
|
||||
}
|
||||
|
||||
select {
|
||||
case v := <-q:
|
||||
t.Fatalf("bad val %v", v)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsite_Conn(t *testing.T) {
|
||||
addr := "localhost:7523"
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
conn := acceptConn(addr)
|
||||
reader := bufio.NewReader(conn)
|
||||
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "gauge.val:1.000000|g\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "key.other:2.000000|kv\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "counter.me:3.000000|c\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err %s", err)
|
||||
}
|
||||
if line != "sample.slow_thingy:4.000000|ms\n" {
|
||||
t.Fatalf("bad line %s", line)
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
done <- true
|
||||
}()
|
||||
s, err := NewStatsiteSink(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("bad error")
|
||||
}
|
||||
|
||||
s.SetGauge([]string{"gauge", "val"}, float32(1))
|
||||
s.EmitKey([]string{"key", "other"}, float32(2))
|
||||
s.IncrCounter([]string{"counter", "me"}, float32(3))
|
||||
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
s.Shutdown()
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("timeout")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
package radix
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRadix(t *testing.T) {
|
||||
var min, max string
|
||||
inp := make(map[string]interface{})
|
||||
for i := 0; i < 1000; i++ {
|
||||
gen := generateUUID()
|
||||
inp[gen] = i
|
||||
if gen < min || i == 0 {
|
||||
min = gen
|
||||
}
|
||||
if gen > max || i == 0 {
|
||||
max = gen
|
||||
}
|
||||
}
|
||||
|
||||
r := NewFromMap(inp)
|
||||
if r.Len() != len(inp) {
|
||||
t.Fatalf("bad length: %v %v", r.Len(), len(inp))
|
||||
}
|
||||
|
||||
r.Walk(func(k string, v interface{}) bool {
|
||||
println(k)
|
||||
return false
|
||||
})
|
||||
|
||||
for k, v := range inp {
|
||||
out, ok := r.Get(k)
|
||||
if !ok {
|
||||
t.Fatalf("missing key: %v", k)
|
||||
}
|
||||
if out != v {
|
||||
t.Fatalf("value mis-match: %v %v", out, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Check min and max
|
||||
outMin, _, _ := r.Minimum()
|
||||
if outMin != min {
|
||||
t.Fatalf("bad minimum: %v %v", outMin, min)
|
||||
}
|
||||
outMax, _, _ := r.Maximum()
|
||||
if outMax != max {
|
||||
t.Fatalf("bad maximum: %v %v", outMax, max)
|
||||
}
|
||||
|
||||
for k, v := range inp {
|
||||
out, ok := r.Delete(k)
|
||||
if !ok {
|
||||
t.Fatalf("missing key: %v", k)
|
||||
}
|
||||
if out != v {
|
||||
t.Fatalf("value mis-match: %v %v", out, v)
|
||||
}
|
||||
}
|
||||
if r.Len() != 0 {
|
||||
t.Fatalf("bad length: %v", r.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoot(t *testing.T) {
|
||||
r := New()
|
||||
_, ok := r.Delete("")
|
||||
if ok {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
_, ok = r.Insert("", true)
|
||||
if ok {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
val, ok := r.Get("")
|
||||
if !ok || val != true {
|
||||
t.Fatalf("bad: %v", val)
|
||||
}
|
||||
val, ok = r.Delete("")
|
||||
if !ok || val != true {
|
||||
t.Fatalf("bad: %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
|
||||
r := New()
|
||||
|
||||
s := []string{"", "A", "AB"}
|
||||
|
||||
for _, ss := range s {
|
||||
r.Insert(ss, true)
|
||||
}
|
||||
|
||||
for _, ss := range s {
|
||||
_, ok := r.Delete(ss)
|
||||
if !ok {
|
||||
t.Fatalf("bad %q", ss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongestPrefix(t *testing.T) {
|
||||
r := New()
|
||||
|
||||
keys := []string{
|
||||
"",
|
||||
"foo",
|
||||
"foobar",
|
||||
"foobarbaz",
|
||||
"foobarbazzip",
|
||||
"foozip",
|
||||
}
|
||||
for _, k := range keys {
|
||||
r.Insert(k, nil)
|
||||
}
|
||||
if r.Len() != len(keys) {
|
||||
t.Fatalf("bad len: %v %v", r.Len(), len(keys))
|
||||
}
|
||||
|
||||
type exp struct {
|
||||
inp string
|
||||
out string
|
||||
}
|
||||
cases := []exp{
|
||||
{"a", ""},
|
||||
{"abc", ""},
|
||||
{"fo", ""},
|
||||
{"foo", "foo"},
|
||||
{"foob", "foo"},
|
||||
{"foobar", "foobar"},
|
||||
{"foobarba", "foobar"},
|
||||
{"foobarbaz", "foobarbaz"},
|
||||
{"foobarbazzi", "foobarbaz"},
|
||||
{"foobarbazzip", "foobarbazzip"},
|
||||
{"foozi", "foo"},
|
||||
{"foozip", "foozip"},
|
||||
{"foozipzap", "foozip"},
|
||||
}
|
||||
for _, test := range cases {
|
||||
m, _, ok := r.LongestPrefix(test.inp)
|
||||
if !ok {
|
||||
t.Fatalf("no match: %v", test)
|
||||
}
|
||||
if m != test.out {
|
||||
t.Fatalf("mis-match: %v %v", m, test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkPrefix(t *testing.T) {
|
||||
r := New()
|
||||
|
||||
keys := []string{
|
||||
"foobar",
|
||||
"foo/bar/baz",
|
||||
"foo/baz/bar",
|
||||
"foo/zip/zap",
|
||||
"zipzap",
|
||||
}
|
||||
for _, k := range keys {
|
||||
r.Insert(k, nil)
|
||||
}
|
||||
if r.Len() != len(keys) {
|
||||
t.Fatalf("bad len: %v %v", r.Len(), len(keys))
|
||||
}
|
||||
|
||||
type exp struct {
|
||||
inp string
|
||||
out []string
|
||||
}
|
||||
cases := []exp{
|
||||
exp{
|
||||
"f",
|
||||
[]string{"foobar", "foo/bar/baz", "foo/baz/bar", "foo/zip/zap"},
|
||||
},
|
||||
exp{
|
||||
"foo",
|
||||
[]string{"foobar", "foo/bar/baz", "foo/baz/bar", "foo/zip/zap"},
|
||||
},
|
||||
exp{
|
||||
"foob",
|
||||
[]string{"foobar"},
|
||||
},
|
||||
exp{
|
||||
"foo/",
|
||||
[]string{"foo/bar/baz", "foo/baz/bar", "foo/zip/zap"},
|
||||
},
|
||||
exp{
|
||||
"foo/b",
|
||||
[]string{"foo/bar/baz", "foo/baz/bar"},
|
||||
},
|
||||
exp{
|
||||
"foo/ba",
|
||||
[]string{"foo/bar/baz", "foo/baz/bar"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar",
|
||||
[]string{"foo/bar/baz"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar/baz",
|
||||
[]string{"foo/bar/baz"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar/bazoo",
|
||||
[]string{},
|
||||
},
|
||||
exp{
|
||||
"z",
|
||||
[]string{"zipzap"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range cases {
|
||||
out := []string{}
|
||||
fn := func(s string, v interface{}) bool {
|
||||
out = append(out, s)
|
||||
return false
|
||||
}
|
||||
r.WalkPrefix(test.inp, fn)
|
||||
sort.Strings(out)
|
||||
sort.Strings(test.out)
|
||||
if !reflect.DeepEqual(out, test.out) {
|
||||
t.Fatalf("mis-match: %v %v", out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkPath(t *testing.T) {
|
||||
r := New()
|
||||
|
||||
keys := []string{
|
||||
"foo",
|
||||
"foo/bar",
|
||||
"foo/bar/baz",
|
||||
"foo/baz/bar",
|
||||
"foo/zip/zap",
|
||||
"zipzap",
|
||||
}
|
||||
for _, k := range keys {
|
||||
r.Insert(k, nil)
|
||||
}
|
||||
if r.Len() != len(keys) {
|
||||
t.Fatalf("bad len: %v %v", r.Len(), len(keys))
|
||||
}
|
||||
|
||||
type exp struct {
|
||||
inp string
|
||||
out []string
|
||||
}
|
||||
cases := []exp{
|
||||
exp{
|
||||
"f",
|
||||
[]string{},
|
||||
},
|
||||
exp{
|
||||
"foo",
|
||||
[]string{"foo"},
|
||||
},
|
||||
exp{
|
||||
"foo/",
|
||||
[]string{"foo"},
|
||||
},
|
||||
exp{
|
||||
"foo/ba",
|
||||
[]string{"foo"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar",
|
||||
[]string{"foo", "foo/bar"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar/baz",
|
||||
[]string{"foo", "foo/bar", "foo/bar/baz"},
|
||||
},
|
||||
exp{
|
||||
"foo/bar/bazoo",
|
||||
[]string{"foo", "foo/bar", "foo/bar/baz"},
|
||||
},
|
||||
exp{
|
||||
"z",
|
||||
[]string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range cases {
|
||||
out := []string{}
|
||||
fn := func(s string, v interface{}) bool {
|
||||
out = append(out, s)
|
||||
return false
|
||||
}
|
||||
r.WalkPath(test.inp, fn)
|
||||
sort.Strings(out)
|
||||
sort.Strings(test.out)
|
||||
if !reflect.DeepEqual(out, test.out) {
|
||||
t.Fatalf("mis-match: %v %v", out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generateUUID is used to generate a random UUID
|
||||
func generateUUID() string {
|
||||
buf := make([]byte, 16)
|
||||
if _, err := crand.Read(buf); err != nil {
|
||||
panic(fmt.Errorf("failed to read random bytes: %v", err))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
|
||||
buf[0:4],
|
||||
buf[4:6],
|
||||
buf[6:8],
|
||||
buf[8:10],
|
||||
buf[10:16])
|
||||
}
|
20
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awstesting/client.go
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awstesting/client.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
package awstesting
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
)
|
||||
|
||||
// NewClient creates and initializes a generic service client for testing.
|
||||
func NewClient(cfgs ...*aws.Config) *client.Client {
|
||||
info := metadata.ClientInfo{
|
||||
Endpoint: "http://endpoint",
|
||||
SigningName: "",
|
||||
}
|
||||
def := defaults.Get()
|
||||
def.Config.MergeIn(cfgs...)
|
||||
|
||||
return client.New(*def.Config, info, def.Handlers)
|
||||
}
|
|
@ -57,16 +57,13 @@ func rcopy(dst, src reflect.Value, root bool) {
|
|||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
if !root {
|
||||
dst.Set(reflect.New(src.Type()).Elem())
|
||||
}
|
||||
|
||||
t := dst.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
name := t.Field(i).Name
|
||||
srcval := src.FieldByName(name)
|
||||
if srcval.IsValid() {
|
||||
rcopy(dst.FieldByName(name), srcval, false)
|
||||
srcVal := src.FieldByName(name)
|
||||
dstVal := dst.FieldByName(name)
|
||||
if srcVal.IsValid() && dstVal.CanSet() {
|
||||
rcopy(dstVal, srcVal, false)
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
|
|
233
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
Normal file
233
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
Normal file
|
@ -0,0 +1,233 @@
|
|||
package awsutil_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func ExampleCopy() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
f1 := &Foo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
assert.Equal(t, f2.A, f1.A)
|
||||
assert.Equal(t, f2.B, f1.B)
|
||||
assert.Equal(t, f2.C, f1.C)
|
||||
|
||||
// But pointers are not!
|
||||
str3 := "nothello"
|
||||
int3 := 57
|
||||
f2.A = 100
|
||||
f2.B[0] = &str3
|
||||
f2.C["B"] = &int3
|
||||
assert.NotEqual(t, f2.A, f1.A)
|
||||
assert.NotEqual(t, f2.B, f1.B)
|
||||
assert.NotEqual(t, f2.C, f1.C)
|
||||
}
|
||||
|
||||
func TestCopyNestedWithUnexported(t *testing.T) {
|
||||
type Bar struct {
|
||||
a int
|
||||
B int
|
||||
}
|
||||
type Foo struct {
|
||||
A string
|
||||
B Bar
|
||||
}
|
||||
|
||||
f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values match
|
||||
assert.Equal(t, f2.A, f1.A)
|
||||
assert.NotEqual(t, f2.B, f1.B)
|
||||
assert.NotEqual(t, f2.B.a, f1.B.a)
|
||||
assert.Equal(t, f2.B.B, f2.B.B)
|
||||
}
|
||||
|
||||
func TestCopyIgnoreNilMembers(t *testing.T) {
|
||||
type Foo struct {
|
||||
A *string
|
||||
B []string
|
||||
C map[string]string
|
||||
}
|
||||
|
||||
f := &Foo{}
|
||||
assert.Nil(t, f.A)
|
||||
assert.Nil(t, f.B)
|
||||
assert.Nil(t, f.C)
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f)
|
||||
assert.Nil(t, f2.A)
|
||||
assert.Nil(t, f2.B)
|
||||
assert.Nil(t, f2.C)
|
||||
|
||||
fcopy := awsutil.CopyOf(f)
|
||||
f3 := fcopy.(*Foo)
|
||||
assert.Nil(t, f3.A)
|
||||
assert.Nil(t, f3.B)
|
||||
assert.Nil(t, f3.C)
|
||||
}
|
||||
|
||||
func TestCopyPrimitive(t *testing.T) {
|
||||
str := "hello"
|
||||
var s string
|
||||
awsutil.Copy(&s, &str)
|
||||
assert.Equal(t, "hello", s)
|
||||
}
|
||||
|
||||
func TestCopyNil(t *testing.T) {
|
||||
var s string
|
||||
awsutil.Copy(&s, nil)
|
||||
assert.Equal(t, "", s)
|
||||
}
|
||||
|
||||
func TestCopyReader(t *testing.T) {
|
||||
var buf io.Reader = bytes.NewReader([]byte("hello world"))
|
||||
var r io.Reader
|
||||
awsutil.Copy(&r, buf)
|
||||
b, err := ioutil.ReadAll(r)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("hello world"), b)
|
||||
|
||||
// empty bytes because this is not a deep copy
|
||||
b, err = ioutil.ReadAll(buf)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte(""), b)
|
||||
}
|
||||
|
||||
func TestCopyDifferentStructs(t *testing.T) {
|
||||
type SrcFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
SrcUnique string
|
||||
SameNameDiffType int
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
type DstFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
DstUnique int
|
||||
SameNameDiffType string
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
f1 := &SrcFoo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
SrcUnique: "unique",
|
||||
SameNameDiffType: 1,
|
||||
unexportedPtr: &int1,
|
||||
ExportedPtr: &int2,
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 DstFoo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
assert.Equal(t, f2.A, f1.A)
|
||||
assert.Equal(t, f2.B, f1.B)
|
||||
assert.Equal(t, f2.C, f1.C)
|
||||
assert.Equal(t, "unique", f1.SrcUnique)
|
||||
assert.Equal(t, 1, f1.SameNameDiffType)
|
||||
assert.Equal(t, 0, f2.DstUnique)
|
||||
assert.Equal(t, "", f2.SameNameDiffType)
|
||||
assert.Equal(t, int1, *f1.unexportedPtr)
|
||||
assert.Nil(t, f2.unexportedPtr)
|
||||
assert.Equal(t, int2, *f1.ExportedPtr)
|
||||
assert.Equal(t, int2, *f2.ExportedPtr)
|
||||
}
|
||||
|
||||
func ExampleCopyOf() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
v := awsutil.CopyOf(f1)
|
||||
var f2 *Foo = v.(*Foo)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
68
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
package awsutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type Struct struct {
|
||||
A []Struct
|
||||
z []Struct
|
||||
B *Struct
|
||||
D *Struct
|
||||
C string
|
||||
}
|
||||
|
||||
var data = Struct{
|
||||
A: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
z: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
|
||||
C: "initial",
|
||||
}
|
||||
|
||||
func TestValueAtPathSuccess(t *testing.T) {
|
||||
assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "C"))
|
||||
assert.Equal(t, []interface{}{"value1"}, awsutil.ValuesAtPath(data, "A[0].C"))
|
||||
assert.Equal(t, []interface{}{"value2"}, awsutil.ValuesAtPath(data, "A[1].C"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[2].C"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtAnyPath(data, "a[2].c"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[-1].C"))
|
||||
assert.Equal(t, []interface{}{"value1", "value2", "value3"}, awsutil.ValuesAtPath(data, "A[].C"))
|
||||
assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C"))
|
||||
assert.Equal(t, []interface{}{"terminal", "terminal2"}, awsutil.ValuesAtPath(data, "B.*.C"))
|
||||
assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "A.D.X || C"))
|
||||
}
|
||||
|
||||
func TestValueAtPathFailure(t *testing.T) {
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "C.x"))
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, ".x"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "X.Y.Z"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[100].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[3].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "B.B.C.Z"))
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "z[-1].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(Struct{}, "A"))
|
||||
}
|
||||
|
||||
func TestSetValueAtPathSuccess(t *testing.T) {
|
||||
var s Struct
|
||||
awsutil.SetValueAtPath(&s, "C", "test1")
|
||||
awsutil.SetValueAtPath(&s, "B.B.C", "test2")
|
||||
awsutil.SetValueAtPath(&s, "B.D.C", "test3")
|
||||
assert.Equal(t, "test1", s.C)
|
||||
assert.Equal(t, "test2", s.B.B.C)
|
||||
assert.Equal(t, "test3", s.B.D.C)
|
||||
|
||||
awsutil.SetValueAtPath(&s, "B.*.C", "test0")
|
||||
assert.Equal(t, "test0", s.B.B.C)
|
||||
assert.Equal(t, "test0", s.B.D.C)
|
||||
|
||||
var s2 Struct
|
||||
awsutil.SetValueAtAnyPath(&s2, "b.b.c", "test0")
|
||||
assert.Equal(t, "test0", s2.B.B.C)
|
||||
awsutil.SetValueAtAnyPath(&s2, "A", []Struct{{}})
|
||||
assert.Equal(t, []Struct{{}}, s2.A)
|
||||
}
|
111
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
111
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// A Config provides configuration to a service client instance.
|
||||
type Config struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
Endpoint, SigningRegion string
|
||||
}
|
||||
|
||||
// ConfigProvider provides a generic way for a service client to receive
|
||||
// the ClientConfig without circular dependencies.
|
||||
type ConfigProvider interface {
|
||||
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// A Client implements the base client request and response handling
|
||||
// used by all service clients.
|
||||
type Client struct {
|
||||
request.Retryer
|
||||
metadata.ClientInfo
|
||||
|
||||
Config aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New will return a pointer to a new initialized service client.
|
||||
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
|
||||
svc := &Client{
|
||||
Config: cfg,
|
||||
ClientInfo: info,
|
||||
Handlers: handlers,
|
||||
}
|
||||
|
||||
maxRetries := aws.IntValue(cfg.MaxRetries)
|
||||
if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
|
||||
maxRetries = 3
|
||||
}
|
||||
svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
|
||||
|
||||
svc.AddDebugHandlers()
|
||||
|
||||
for _, option := range options {
|
||||
option(svc)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// NewRequest returns a new Request pointer for the service API
|
||||
// operation and parameters.
|
||||
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||
return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
|
||||
}
|
||||
|
||||
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||
// debug information.
|
||||
func (c *Client) AddDebugHandlers() {
|
||||
if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Handlers.Send.PushFront(logRequest)
|
||||
c.Handlers.Send.PushBack(logResponse)
|
||||
}
|
||||
|
||||
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||
---[ REQUEST POST-SIGN ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
---[ RESPONSE ]--------------------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no reponse data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
}
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
package service
|
||||
package client
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
|
@ -22,16 +21,13 @@ import (
|
|||
// // This implementation always has 100 max retries
|
||||
// func (d retryer) MaxRetries() uint { return 100 }
|
||||
type DefaultRetryer struct {
|
||||
*Service
|
||||
NumMaxRetries int
|
||||
}
|
||||
|
||||
// MaxRetries returns the number of maximum returns the service will use to make
|
||||
// an individual API request.
|
||||
func (d DefaultRetryer) MaxRetries() uint {
|
||||
if aws.IntValue(d.Service.Config.MaxRetries) < 0 {
|
||||
return d.DefaultMaxRetries
|
||||
}
|
||||
return uint(aws.IntValue(d.Service.Config.MaxRetries))
|
||||
func (d DefaultRetryer) MaxRetries() int {
|
||||
return d.NumMaxRetries
|
||||
}
|
||||
|
||||
// RetryRules returns the delay duration before retrying this request again
|
12
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package metadata
|
||||
|
||||
// ClientInfo wraps immutable data from the client.Client structure.
|
||||
type ClientInfo struct {
|
||||
ServiceName string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
SigningRegion string
|
||||
JSONVersion string
|
||||
TargetPrefix string
|
||||
}
|
|
@ -7,15 +7,17 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// DefaultRetries is the default number of retries for a service. The value of
|
||||
// -1 indicates that the service specific retry default will be used.
|
||||
const DefaultRetries = -1
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own default
|
||||
// number of retries. This will be the default action if Config.MaxRetries
|
||||
// is nil also.
|
||||
const UseServiceDefaultRetries = -1
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the {defaults.DefaultConfig} structure.
|
||||
type Config struct {
|
||||
// The credentials object to use when signing requests. Defaults to
|
||||
// {defaults.DefaultChainCredentials}.
|
||||
// a chain of credential providers to search for credentials in environment
|
||||
// variables, shared credential file, and EC2 Instance Roles.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||
|
@ -171,15 +173,17 @@ func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// Merge returns a new Config with the other Config's attribute values merged into
|
||||
// this Config. If the other Config's attribute is nil it will not be merged into
|
||||
// the new Config to be returned.
|
||||
func (c Config) Merge(other *Config) *Config {
|
||||
if other == nil {
|
||||
return &c
|
||||
// MergeIn merges the passed in configs into the existing config object.
|
||||
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||
for _, other := range cfgs {
|
||||
mergeInConfig(c, other)
|
||||
}
|
||||
}
|
||||
|
||||
dst := c
|
||||
func mergeInConfig(dst *Config, other *Config) {
|
||||
if other == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if other.Credentials != nil {
|
||||
dst.Credentials = other.Credentials
|
||||
|
@ -228,12 +232,17 @@ func (c Config) Merge(other *Config) *Config {
|
|||
if other.SleepDelay != nil {
|
||||
dst.SleepDelay = other.SleepDelay
|
||||
}
|
||||
|
||||
return &dst
|
||||
}
|
||||
|
||||
// Copy will return a shallow copy of the Config object.
|
||||
func (c Config) Copy() *Config {
|
||||
dst := c
|
||||
return &dst
|
||||
// Copy will return a shallow copy of the Config object. If any additional
|
||||
// configurations are provided they will be merged into the new config returned.
|
||||
func (c *Config) Copy(cfgs ...*Config) *Config {
|
||||
dst := &Config{}
|
||||
dst.MergeIn(c)
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
dst.MergeIn(cfg)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
|
86
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
Normal file
86
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
|
||||
var copyTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("CopyTestEndpoint"),
|
||||
Region: String("COPY_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(3),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if !reflect.DeepEqual(*got, want) {
|
||||
t.Errorf("Copy() = %+v", got)
|
||||
t.Errorf(" want %+v", want)
|
||||
}
|
||||
|
||||
got.Region = String("other")
|
||||
if got.Region == want.Region {
|
||||
t.Errorf("Expect setting copy values not not reflect in source")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReturnsNewInstance(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if got == &want {
|
||||
t.Errorf("Copy() = %p; want different instance as source %p", got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
var mergeTestZeroValueConfig = Config{}
|
||||
|
||||
var mergeTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("MergeTestEndpoint"),
|
||||
Region: String("MERGE_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(10),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
var mergeTests = []struct {
|
||||
cfg *Config
|
||||
in *Config
|
||||
want *Config
|
||||
}{
|
||||
{&Config{}, nil, &Config{}},
|
||||
{&Config{}, &mergeTestZeroValueConfig, &Config{}},
|
||||
{&Config{}, &mergeTestConfig, &mergeTestConfig},
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for i, tt := range mergeTests {
|
||||
got := tt.cfg.Copy()
|
||||
got.MergeIn(tt.in)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Config %d %+v", i, tt.cfg)
|
||||
t.Errorf(" Merge(%+v)", tt.in)
|
||||
t.Errorf(" got %+v", got)
|
||||
t.Errorf(" want %+v", tt.want)
|
||||
}
|
||||
}
|
||||
}
|
437
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
Normal file
437
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
Normal file
|
@ -0,0 +1,437 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testCasesStringSlice = [][]string{
|
||||
{"a", "b", "c", "d", "e"},
|
||||
{"a", "b", "", "", "e"},
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := StringValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringValueSlice = [][]*string{
|
||||
{String("a"), String("b"), nil, String("c")},
|
||||
}
|
||||
|
||||
func TestStringValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringMap = []map[string]string{
|
||||
{"a": "1", "b": "2", "c": "3"},
|
||||
}
|
||||
|
||||
func TestStringMap(t *testing.T) {
|
||||
for idx, in := range testCasesStringMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringMap(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := StringValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolSlice = [][]bool{
|
||||
{true, true, false, false},
|
||||
}
|
||||
|
||||
func TestBoolSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := BoolValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolValueSlice = [][]*bool{}
|
||||
|
||||
func TestBoolValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolMap = []map[string]bool{
|
||||
{"a": true, "b": false, "c": true},
|
||||
}
|
||||
|
||||
func TestBoolMap(t *testing.T) {
|
||||
for idx, in := range testCasesBoolMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolMap(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := BoolValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntSlice = [][]int{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestIntSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := IntValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntValueSlice = [][]*int{}
|
||||
|
||||
func TestIntValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntMap = []map[string]int{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestIntMap(t *testing.T) {
|
||||
for idx, in := range testCasesIntMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntMap(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := IntValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Slice = [][]int64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestInt64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Slice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := Int64ValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64ValueSlice = [][]*int64{}
|
||||
|
||||
func TestInt64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64ValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64Slice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Map = []map[string]int64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestInt64Map(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Map(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := Int64ValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Slice = [][]float64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestFloat64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Slice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := Float64ValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64ValueSlice = [][]*float64{}
|
||||
|
||||
func TestFloat64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64ValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64Slice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Map = []map[string]float64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestFloat64Map(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Map(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := Float64ValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeSlice = [][]time.Time{
|
||||
{time.Now(), time.Now().AddDate(100, 0, 0)},
|
||||
}
|
||||
|
||||
func TestTimeSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := TimeValueSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeValueSlice = [][]*time.Time{}
|
||||
|
||||
func TestTimeValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeValueSlice(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeSlice(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeMap = []map[string]time.Time{
|
||||
{"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()},
|
||||
}
|
||||
|
||||
func TestTimeMap(t *testing.T) {
|
||||
for idx, in := range testCasesTimeMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeMap(in)
|
||||
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
|
||||
for i := range out {
|
||||
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
|
||||
}
|
||||
|
||||
out2 := TimeValueMap(out)
|
||||
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
|
||||
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
|||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{"core.SendHandler", func(r *request.Request) {
|
||||
var err error
|
||||
r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
|
||||
r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest)
|
||||
if err != nil {
|
||||
// Capture the case where url.Error is returned for error processing
|
||||
// response. e.g. 301 without location header comes back as string
|
||||
|
@ -110,13 +110,13 @@ var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *r
|
|||
|
||||
if r.WillRetry() {
|
||||
r.RetryDelay = r.RetryRules(r)
|
||||
r.Service.Config.SleepDelay(r.RetryDelay)
|
||||
r.Config.SleepDelay(r.RetryDelay)
|
||||
|
||||
// when the expired token exception occurs the credentials
|
||||
// need to be expired locally so that the next request to
|
||||
// get credentials will trigger a credentials refresh.
|
||||
if r.IsErrorExpired() {
|
||||
r.Service.Config.Credentials.Expire()
|
||||
r.Config.Credentials.Expire()
|
||||
}
|
||||
|
||||
r.RetryCount++
|
||||
|
@ -128,9 +128,9 @@ var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *r
|
|||
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
|
||||
// region is not valid.
|
||||
var ValidateEndpointHandler = request.NamedHandler{"core.ValidateEndpointHandler", func(r *request.Request) {
|
||||
if r.Service.SigningRegion == "" && aws.StringValue(r.Service.Config.Region) == "" {
|
||||
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||
r.Error = aws.ErrMissingRegion
|
||||
} else if r.Service.Endpoint == "" {
|
||||
} else if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}}
|
||||
|
|
113
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
Normal file
113
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awstesting"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func TestValidateEndpointHandler(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2"))
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestValidateEndpointHandlerErrorRegion(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient()
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, aws.ErrMissingRegion, err)
|
||||
}
|
||||
|
||||
type mockCredsProvider struct {
|
||||
expired bool
|
||||
retrieveCalled bool
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) Retrieve() (credentials.Value, error) {
|
||||
m.retrieveCalled = true
|
||||
return credentials.Value{}, nil
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) IsExpired() bool {
|
||||
return m.expired
|
||||
}
|
||||
|
||||
func TestAfterRetryRefreshCreds(t *testing.T) {
|
||||
os.Clearenv()
|
||||
credProvider := &mockCredsProvider{}
|
||||
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewCredentials(credProvider),
|
||||
MaxRetries: aws.Int(1),
|
||||
})
|
||||
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("UnknownError", "", nil)
|
||||
r.HTTPResponse = &http.Response{StatusCode: 400}
|
||||
})
|
||||
svc.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("ExpiredTokenException", "", nil)
|
||||
})
|
||||
svc.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
|
||||
assert.True(t, svc.Config.Credentials.IsExpired(), "Expect to start out expired")
|
||||
assert.False(t, credProvider.retrieveCalled)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
req.Send()
|
||||
|
||||
assert.True(t, svc.Config.Credentials.IsExpired())
|
||||
assert.False(t, credProvider.retrieveCalled)
|
||||
|
||||
_, err := svc.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, credProvider.retrieveCalled)
|
||||
}
|
||||
|
||||
type testSendHandlerTransport struct{}
|
||||
|
||||
func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
return nil, fmt.Errorf("mock error")
|
||||
}
|
||||
|
||||
func TestSendHandlerError(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
HTTPClient: &http.Client{
|
||||
Transport: &testSendHandlerTransport{},
|
||||
},
|
||||
})
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
r.Send()
|
||||
|
||||
assert.Error(t, r.Error)
|
||||
assert.NotNil(t, r.HTTPResponse)
|
||||
}
|
134
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go
generated
vendored
Normal file
134
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testSvc = func() *client.Client {
|
||||
s := &client.Client{
|
||||
Config: aws.Config{},
|
||||
ClientInfo: metadata.ClientInfo{
|
||||
ServiceName: "mock-service",
|
||||
APIVersion: "2015-01-01",
|
||||
},
|
||||
}
|
||||
return s
|
||||
}()
|
||||
|
||||
type StructShape struct {
|
||||
RequiredList []*ConditionalStructShape `required:"true"`
|
||||
RequiredMap map[string]*ConditionalStructShape `required:"true"`
|
||||
RequiredBool *bool `required:"true"`
|
||||
OptionalStruct *ConditionalStructShape
|
||||
|
||||
hiddenParameter *string
|
||||
|
||||
metadataStructureShape
|
||||
}
|
||||
|
||||
type metadataStructureShape struct {
|
||||
SDKShapeTraits bool
|
||||
}
|
||||
|
||||
type ConditionalStructShape struct {
|
||||
Name *string `required:"true"`
|
||||
SDKShapeTraits bool
|
||||
}
|
||||
|
||||
func TestNoErrors(t *testing.T) {
|
||||
input := &StructShape{
|
||||
RequiredList: []*ConditionalStructShape{},
|
||||
RequiredMap: map[string]*ConditionalStructShape{
|
||||
"key1": {Name: aws.String("Name")},
|
||||
"key2": {Name: aws.String("Name")},
|
||||
},
|
||||
RequiredBool: aws.Bool(true),
|
||||
OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")},
|
||||
}
|
||||
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
require.NoError(t, req.Error)
|
||||
}
|
||||
|
||||
func TestMissingRequiredParameters(t *testing.T) {
|
||||
input := &StructShape{}
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
require.Error(t, req.Error)
|
||||
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
|
||||
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", req.Error.(awserr.Error).Message())
|
||||
}
|
||||
|
||||
func TestNestedMissingRequiredParameters(t *testing.T) {
|
||||
input := &StructShape{
|
||||
RequiredList: []*ConditionalStructShape{{}},
|
||||
RequiredMap: map[string]*ConditionalStructShape{
|
||||
"key1": {Name: aws.String("Name")},
|
||||
"key2": {},
|
||||
},
|
||||
RequiredBool: aws.Bool(true),
|
||||
OptionalStruct: &ConditionalStructShape{},
|
||||
}
|
||||
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
require.Error(t, req.Error)
|
||||
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
|
||||
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", req.Error.(awserr.Error).Message())
|
||||
}
|
||||
|
||||
type testInput struct {
|
||||
StringField string `min:"5"`
|
||||
PtrStrField *string `min:"2"`
|
||||
ListField []string `min:"3"`
|
||||
MapField map[string]string `min:"4"`
|
||||
}
|
||||
|
||||
var testsFieldMin = []struct {
|
||||
err awserr.Error
|
||||
in testInput
|
||||
}{
|
||||
{
|
||||
err: awserr.New("InvalidParameter", "1 validation errors:\n- field too short, minimum length 5: StringField", nil),
|
||||
in: testInput{StringField: "abcd"},
|
||||
},
|
||||
{
|
||||
err: awserr.New("InvalidParameter", "2 validation errors:\n- field too short, minimum length 5: StringField\n- field too short, minimum length 3: ListField", nil),
|
||||
in: testInput{StringField: "abcd", ListField: []string{"a", "b"}},
|
||||
},
|
||||
{
|
||||
err: awserr.New("InvalidParameter", "3 validation errors:\n- field too short, minimum length 5: StringField\n- field too short, minimum length 3: ListField\n- field too short, minimum length 4: MapField", nil),
|
||||
in: testInput{StringField: "abcd", ListField: []string{"a", "b"}, MapField: map[string]string{"a": "a", "b": "b"}},
|
||||
},
|
||||
{
|
||||
err: awserr.New("InvalidParameter", "1 validation errors:\n- field too short, minimum length 2: PtrStrField", nil),
|
||||
in: testInput{StringField: "abcde", PtrStrField: aws.String("v")},
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
in: testInput{StringField: "abcde", PtrStrField: aws.String("value"),
|
||||
ListField: []string{"a", "b", "c"}, MapField: map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}},
|
||||
},
|
||||
}
|
||||
|
||||
func TestValidateFieldMinParameter(t *testing.T) {
|
||||
for i, c := range testsFieldMin {
|
||||
req := testSvc.NewRequest(&request.Operation{}, &c.in, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
require.Equal(t, c.err, req.Error, "%d case failed", i)
|
||||
}
|
||||
}
|
73
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go
generated
vendored
Normal file
73
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestChainProviderGet(t *testing.T) {
|
||||
p := &ChainProvider{
|
||||
Providers: []Provider{
|
||||
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
|
||||
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
|
||||
&stubProvider{
|
||||
creds: Value{
|
||||
AccessKeyID: "AKID",
|
||||
SecretAccessKey: "SECRET",
|
||||
SessionToken: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect session token to be empty")
|
||||
}
|
||||
|
||||
func TestChainProviderIsExpired(t *testing.T) {
|
||||
stubProvider := &stubProvider{expired: true}
|
||||
p := &ChainProvider{
|
||||
Providers: []Provider{
|
||||
stubProvider,
|
||||
},
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect expired to be true before any Retrieve")
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.False(t, p.IsExpired(), "Expect not expired after retrieve")
|
||||
|
||||
stubProvider.expired = true
|
||||
assert.True(t, p.IsExpired(), "Expect return of expired provider")
|
||||
|
||||
_, err = p.Retrieve()
|
||||
assert.False(t, p.IsExpired(), "Expect not expired after retrieve")
|
||||
}
|
||||
|
||||
func TestChainProviderWithNoProvider(t *testing.T) {
|
||||
p := &ChainProvider{
|
||||
Providers: []Provider{},
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect expired with no providers")
|
||||
_, err := p.Retrieve()
|
||||
assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
|
||||
}
|
||||
|
||||
func TestChainProviderWithNoValidProvider(t *testing.T) {
|
||||
p := &ChainProvider{
|
||||
Providers: []Provider{
|
||||
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
|
||||
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
|
||||
},
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect expired with no providers")
|
||||
_, err := p.Retrieve()
|
||||
assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
|
||||
}
|
62
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go
generated
vendored
Normal file
62
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type stubProvider struct {
|
||||
creds Value
|
||||
expired bool
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *stubProvider) Retrieve() (Value, error) {
|
||||
s.expired = false
|
||||
return s.creds, s.err
|
||||
}
|
||||
func (s *stubProvider) IsExpired() bool {
|
||||
return s.expired
|
||||
}
|
||||
|
||||
func TestCredentialsGet(t *testing.T) {
|
||||
c := NewCredentials(&stubProvider{
|
||||
creds: Value{
|
||||
AccessKeyID: "AKID",
|
||||
SecretAccessKey: "SECRET",
|
||||
SessionToken: "",
|
||||
},
|
||||
expired: true,
|
||||
})
|
||||
|
||||
creds, err := c.Get()
|
||||
assert.Nil(t, err, "Expected no error")
|
||||
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect session token to be empty")
|
||||
}
|
||||
|
||||
func TestCredentialsGetWithError(t *testing.T) {
|
||||
c := NewCredentials(&stubProvider{err: awserr.New("provider error", "", nil), expired: true})
|
||||
|
||||
_, err := c.Get()
|
||||
assert.Equal(t, "provider error", err.(awserr.Error).Code(), "Expected provider error")
|
||||
}
|
||||
|
||||
func TestCredentialsExpire(t *testing.T) {
|
||||
stub := &stubProvider{}
|
||||
c := NewCredentials(stub)
|
||||
|
||||
stub.expired = false
|
||||
assert.True(t, c.IsExpired(), "Expected to start out expired")
|
||||
c.Expire()
|
||||
assert.True(t, c.IsExpired(), "Expected to be expired")
|
||||
|
||||
c.forceRefresh = false
|
||||
assert.False(t, c.IsExpired(), "Expected not to be expired")
|
||||
|
||||
stub.expired = true
|
||||
assert.True(t, c.IsExpired(), "Expected to be expired")
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
)
|
||||
|
@ -25,9 +26,6 @@ import (
|
|||
// Client: &http.Client{
|
||||
// Timeout: 10 * time.Second,
|
||||
// },
|
||||
// // Use default EC2 Role metadata endpoint, Alternate endpoints can be
|
||||
// // specified setting Endpoint to something else.
|
||||
// Endpoint: "",
|
||||
// // Do not use early expiry of credentials. If a non zero value is
|
||||
// // specified the credentials will be expired early
|
||||
// ExpiryWindow: 0,
|
||||
|
@ -35,8 +33,8 @@ import (
|
|||
type EC2RoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// EC2Metadata client to use when connecting to EC2 metadata service
|
||||
Client *ec2metadata.Client
|
||||
// Required EC2Metadata client to use when connecting to EC2 metadata service.
|
||||
Client *ec2metadata.EC2Metadata
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
|
@ -50,33 +48,40 @@ type EC2RoleProvider struct {
|
|||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object
|
||||
// wrapping the EC2RoleProvider.
|
||||
//
|
||||
// Takes a custom http.Client which can be configured for custom handling of
|
||||
// things such as timeout.
|
||||
//
|
||||
// Endpoint is the URL that the EC2RoleProvider will connect to when retrieving
|
||||
// role and credentials.
|
||||
//
|
||||
// Window is the expiry window that will be subtracted from the expiry returned
|
||||
// by the role credential request. This is done so that the credentials will
|
||||
// expire sooner than their actual lifespan.
|
||||
func NewCredentials(client *ec2metadata.Client, window time.Duration) *credentials.Credentials {
|
||||
return credentials.NewCredentials(&EC2RoleProvider{
|
||||
Client: client,
|
||||
ExpiryWindow: window,
|
||||
})
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
|
||||
// The ConfigProvider is satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: ec2metadata.New(c),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
|
||||
// metadata service.
|
||||
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: client,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve retrieves credentials from the EC2 service.
|
||||
// Error will be returned if the request fails, or unable to extract
|
||||
// the desired credentials.
|
||||
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||
if m.Client == nil {
|
||||
m.Client = ec2metadata.New(nil)
|
||||
}
|
||||
|
||||
credsList, err := requestCredList(m.Client)
|
||||
if err != nil {
|
||||
return credentials.Value{}, err
|
||||
|
@ -101,7 +106,7 @@ func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// A ec2RoleCredRespBody provides the shape for deserializing credential
|
||||
// A ec2RoleCredRespBody provides the shape for unmarshalling credential
|
||||
// request responses.
|
||||
type ec2RoleCredRespBody struct {
|
||||
// Success State
|
||||
|
@ -119,7 +124,7 @@ const iamSecurityCredsPath = "/iam/security-credentials"
|
|||
|
||||
// requestCredList requests a list of credentials from the EC2 service.
|
||||
// If there are no credentials, or there is an error making or receiving the request
|
||||
func requestCredList(client *ec2metadata.Client) ([]string, error) {
|
||||
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||
resp, err := client.GetMetadata(iamSecurityCredsPath)
|
||||
if err != nil {
|
||||
return nil, awserr.New("EC2RoleRequestError", "failed to list EC2 Roles", err)
|
||||
|
@ -142,7 +147,7 @@ func requestCredList(client *ec2metadata.Client) ([]string, error) {
|
|||
//
|
||||
// If the credentials cannot be found, or there is an error reading the response
|
||||
// and error will be returned.
|
||||
func requestCred(client *ec2metadata.Client, credsName string) (ec2RoleCredRespBody, error) {
|
||||
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||
resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName))
|
||||
if err != nil {
|
||||
return ec2RoleCredRespBody{},
|
||||
|
|
159
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go
generated
vendored
Normal file
159
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,159 @@
|
|||
package ec2rolecreds_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
const credsRespTmpl = `{
|
||||
"Code": "Success",
|
||||
"Type": "AWS-HMAC",
|
||||
"AccessKeyId" : "accessKey",
|
||||
"SecretAccessKey" : "secret",
|
||||
"Token" : "token",
|
||||
"Expiration" : "%s",
|
||||
"LastUpdated" : "2009-11-23T0:00:00Z"
|
||||
}`
|
||||
|
||||
const credsFailRespTmpl = `{
|
||||
"Code": "ErrorCode",
|
||||
"Message": "ErrorMsg",
|
||||
"LastUpdated": "2009-11-23T0:00:00Z"
|
||||
}`
|
||||
|
||||
func initTestServer(expireOn string, failAssume bool) *httptest.Server {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/latest/meta-data/iam/security-credentials" {
|
||||
fmt.Fprintln(w, "RoleName")
|
||||
} else if r.URL.Path == "/latest/meta-data/iam/security-credentials/RoleName" {
|
||||
if failAssume {
|
||||
fmt.Fprintf(w, credsFailRespTmpl)
|
||||
} else {
|
||||
fmt.Fprintf(w, credsRespTmpl, expireOn)
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
}
|
||||
}))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestEC2RoleProvider(t *testing.T) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", false)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func TestEC2RoleProviderFailAssume(t *testing.T) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", true)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
assert.Error(t, err, "Expect error")
|
||||
|
||||
e := err.(awserr.Error)
|
||||
assert.Equal(t, "ErrorCode", e.Code())
|
||||
assert.Equal(t, "ErrorMsg", e.Message())
|
||||
assert.Nil(t, e.OrigErr())
|
||||
|
||||
assert.Equal(t, "", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func TestEC2RoleProviderIsExpired(t *testing.T) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", false)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
|
||||
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
|
||||
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(3014, 12, 15, 21, 26, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired.")
|
||||
}
|
||||
|
||||
func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", false)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
ExpiryWindow: time.Hour * 1,
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(2014, 12, 15, 0, 51, 37, 0, time.UTC)
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
|
||||
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
|
||||
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(2014, 12, 16, 0, 55, 37, 0, time.UTC)
|
||||
}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired.")
|
||||
}
|
||||
|
||||
func BenchmarkEC3RoleProvider(b *testing.B) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", false)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := p.Retrieve(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
70
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go
generated
vendored
Normal file
70
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnvProviderRetrieve(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "access")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
os.Setenv("AWS_SESSION_TOKEN", "token")
|
||||
|
||||
e := EnvProvider{}
|
||||
creds, err := e.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func TestEnvProviderIsExpired(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "access")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
os.Setenv("AWS_SESSION_TOKEN", "token")
|
||||
|
||||
e := EnvProvider{}
|
||||
|
||||
assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.")
|
||||
|
||||
_, err := e.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.")
|
||||
}
|
||||
|
||||
func TestEnvProviderNoAccessKeyID(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
|
||||
e := EnvProvider{}
|
||||
creds, err := e.Retrieve()
|
||||
assert.Equal(t, ErrAccessKeyIDNotFound, err, "ErrAccessKeyIDNotFound expected, but was %#v error: %#v", creds, err)
|
||||
}
|
||||
|
||||
func TestEnvProviderNoSecretAccessKey(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "access")
|
||||
|
||||
e := EnvProvider{}
|
||||
creds, err := e.Retrieve()
|
||||
assert.Equal(t, ErrSecretAccessKeyNotFound, err, "ErrSecretAccessKeyNotFound expected, but was %#v error: %#v", creds, err)
|
||||
}
|
||||
|
||||
func TestEnvProviderAlternateNames(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_ACCESS_KEY", "access")
|
||||
os.Setenv("AWS_SECRET_KEY", "secret")
|
||||
|
||||
e := EnvProvider{}
|
||||
creds, err := e.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "access", creds.AccessKeyID, "Expected access key ID")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expected secret access key")
|
||||
assert.Empty(t, creds.SessionToken, "Expected no token")
|
||||
}
|
88
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go
generated
vendored
Normal file
88
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSharedCredentialsProvider(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func TestSharedCredentialsProviderIsExpired(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
|
||||
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve")
|
||||
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve")
|
||||
}
|
||||
|
||||
func TestSharedCredentialsProviderWithAWS_SHARED_CREDENTIALS_FILE(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "example.ini")
|
||||
p := SharedCredentialsProvider{}
|
||||
creds, err := p.Retrieve()
|
||||
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func TestSharedCredentialsProviderWithAWS_PROFILE(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "no_token")
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect no token")
|
||||
}
|
||||
|
||||
func TestSharedCredentialsProviderWithoutTokenFromProfile(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: "no_token"}
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect no token")
|
||||
}
|
||||
|
||||
func BenchmarkSharedCredentialsProvider(b *testing.B) {
|
||||
os.Clearenv()
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
34
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStaticProviderGet(t *testing.T) {
|
||||
s := StaticProvider{
|
||||
Value: Value{
|
||||
AccessKeyID: "AKID",
|
||||
SecretAccessKey: "SECRET",
|
||||
SessionToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
creds, err := s.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect no session token")
|
||||
}
|
||||
|
||||
func TestStaticProviderIsExpired(t *testing.T) {
|
||||
s := StaticProvider{
|
||||
Value: Value{
|
||||
AccessKeyID: "AKID",
|
||||
SecretAccessKey: "SECRET",
|
||||
SessionToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
assert.False(t, s.IsExpired(), "Expect static credentials to never expire")
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
@ -18,31 +19,17 @@ type AssumeRoler interface {
|
|||
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||
}
|
||||
|
||||
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||
// will be valid for.
|
||||
var DefaultDuration = time.Duration(15) * time.Minute
|
||||
|
||||
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||
// keeps track of their expiration time. This provider must be used explicitly,
|
||||
// as it is not included in the credentials chain.
|
||||
//
|
||||
// Example how to configure a service to use this provider:
|
||||
//
|
||||
// config := &aws.Config{
|
||||
// Credentials: stscreds.NewCredentials(nil, "arn-of-the-role-to-assume", 10*time.Second),
|
||||
// })
|
||||
// // Use config for creating your AWS service.
|
||||
//
|
||||
// Example how to obtain customised credentials:
|
||||
//
|
||||
// provider := &stscreds.Provider{
|
||||
// // Extend the duration to 1 hour.
|
||||
// Duration: time.Hour,
|
||||
// // Custom role name.
|
||||
// RoleSessionName: "custom-session-name",
|
||||
// }
|
||||
// creds := credentials.NewCredentials(provider)
|
||||
//
|
||||
type AssumeRoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// Custom STS client. If not set the default STS client will be used.
|
||||
// STS client to make assume role request with.
|
||||
Client AssumeRoler
|
||||
|
||||
// Role to be assumed.
|
||||
|
@ -70,37 +57,55 @@ type AssumeRoleProvider struct {
|
|||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// The sts and roleARN parameters are used for building the "AssumeRole" call.
|
||||
// Pass nil as sts to use the default client.
|
||||
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||
// satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: sts.New(c),
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Window is the expiry window that will be subtracted from the expiry returned
|
||||
// by the role credential request. This is done so that the credentials will
|
||||
// expire sooner than their actual lifespan.
|
||||
func NewCredentials(client AssumeRoler, roleARN string, window time.Duration) *credentials.Credentials {
|
||||
return credentials.NewCredentials(&AssumeRoleProvider{
|
||||
Client: client,
|
||||
RoleARN: roleARN,
|
||||
ExpiryWindow: window,
|
||||
})
|
||||
// Takes an AssumeRoler which can be satisfiede by the STS client.
|
||||
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: svc,
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve generates a new set of temporary credentials using STS.
|
||||
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||
|
||||
// Apply defaults where parameters are not set.
|
||||
if p.Client == nil {
|
||||
p.Client = sts.New(nil)
|
||||
}
|
||||
if p.RoleSessionName == "" {
|
||||
// Try to work out a role name that will hopefully end up unique.
|
||||
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
|
||||
}
|
||||
if p.Duration == 0 {
|
||||
// Expire as often as AWS permits.
|
||||
p.Duration = 15 * time.Minute
|
||||
p.Duration = DefaultDuration
|
||||
}
|
||||
|
||||
roleOutput, err := p.Client.AssumeRole(&sts.AssumeRoleInput{
|
||||
|
|
56
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go
generated
vendored
Normal file
56
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
package stscreds
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type stubSTS struct {
|
||||
}
|
||||
|
||||
func (s *stubSTS) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
|
||||
expiry := time.Now().Add(60 * time.Minute)
|
||||
return &sts.AssumeRoleOutput{
|
||||
Credentials: &sts.Credentials{
|
||||
// Just reflect the role arn to the provider.
|
||||
AccessKeyId: input.RoleArn,
|
||||
SecretAccessKey: aws.String("assumedSecretAccessKey"),
|
||||
SessionToken: aws.String("assumedSessionToken"),
|
||||
Expiration: &expiry,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestAssumeRoleProvider(t *testing.T) {
|
||||
stub := &stubSTS{}
|
||||
p := &AssumeRoleProvider{
|
||||
Client: stub,
|
||||
RoleARN: "roleARN",
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "roleARN", creds.AccessKeyID, "Expect access key ID to be reflected role ARN")
|
||||
assert.Equal(t, "assumedSecretAccessKey", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, "assumedSessionToken", creds.SessionToken, "Expect session token to match")
|
||||
}
|
||||
|
||||
func BenchmarkAssumeRoleProvider(b *testing.B) {
|
||||
stub := &stubSTS{}
|
||||
p := &AssumeRoleProvider{
|
||||
Client: stub,
|
||||
RoleARN: "roleARN",
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := p.Retrieve(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// Package defaults is a collection of helpers to retrieve the SDK's default
|
||||
// configuration and handlers.
|
||||
package defaults
|
||||
|
||||
import (
|
||||
|
@ -6,34 +8,69 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// DefaultChainCredentials is a Credentials which will find the first available
|
||||
// credentials Value from the list of Providers.
|
||||
//
|
||||
// This should be used in the default case. Once the type of credentials are
|
||||
// known switching to the specific Credentials will be more efficient.
|
||||
var DefaultChainCredentials = credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
|
||||
})
|
||||
// A Defaults provides a collection of default values for SDK clients.
|
||||
type Defaults struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// DefaultConfig is the default all service configuration will be based off of.
|
||||
// By default, all clients use this structure for initialization options unless
|
||||
// a custom configuration object is passed in.
|
||||
//
|
||||
// You may modify this global structure to change all default configuration
|
||||
// in the SDK. Note that configuration options are copied by value, so any
|
||||
// modifications must happen before constructing a client.
|
||||
var DefaultConfig = aws.NewConfig().
|
||||
WithCredentials(DefaultChainCredentials).
|
||||
WithRegion(os.Getenv("AWS_REGION")).
|
||||
WithHTTPClient(http.DefaultClient).
|
||||
WithMaxRetries(aws.DefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithSleepDelay(time.Sleep)
|
||||
// Get returns the SDK's default values with Config and handlers pre-configured.
|
||||
func Get() Defaults {
|
||||
cfg := Config()
|
||||
handlers := Handlers()
|
||||
cfg.Credentials = CredChain(cfg, handlers)
|
||||
|
||||
return Defaults{
|
||||
Config: cfg,
|
||||
Handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// Config returns the default configuration.
|
||||
func Config() *aws.Config {
|
||||
return aws.NewConfig().
|
||||
WithCredentials(credentials.AnonymousCredentials).
|
||||
WithRegion(os.Getenv("AWS_REGION")).
|
||||
WithHTTPClient(http.DefaultClient).
|
||||
WithMaxRetries(aws.UseServiceDefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithSleepDelay(time.Sleep)
|
||||
}
|
||||
|
||||
// Handlers returns the default request handlers.
|
||||
func Handlers() request.Handlers {
|
||||
var handlers request.Handlers
|
||||
|
||||
handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
handlers.Build.PushBackNamed(corehandlers.UserAgentHandler)
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
// CredChain returns the default credential chain.
|
||||
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, *cfg.Region, true)
|
||||
|
||||
return credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(*cfg, handlers, endpoint, signingRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
// GetMetadata uses the path provided to request
|
||||
func (c *Client) GetMetadata(p string) (string, error) {
|
||||
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
|
@ -15,13 +15,13 @@ func (c *Client) GetMetadata(p string) (string, error) {
|
|||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := request.New(c.Service.ServiceInfo, c.Service.Handlers, c.Service.Retryer, op, nil, output)
|
||||
req := c.NewRequest(op, nil, output)
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// Region returns the region the instance is running in.
|
||||
func (c *Client) Region() (string, error) {
|
||||
func (c *EC2Metadata) Region() (string, error) {
|
||||
resp, err := c.GetMetadata("placement/availability-zone")
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -34,7 +34,7 @@ func (c *Client) Region() (string, error) {
|
|||
// Available returns if the application has access to the EC2 Metadata service.
|
||||
// Can be used to determine if application is running within an EC2 Instance and
|
||||
// the metadata service is available.
|
||||
func (c *Client) Available() bool {
|
||||
func (c *EC2Metadata) Available() bool {
|
||||
if _, err := c.GetMetadata("instance-id"); err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
101
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go
generated
vendored
Normal file
101
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
package ec2metadata_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
func initTestServer(path string, resp string) *httptest.Server {
|
||||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.RequestURI != path {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(resp))
|
||||
}))
|
||||
}
|
||||
|
||||
func TestEndpoint(t *testing.T) {
|
||||
c := ec2metadata.New(session.New())
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: path.Join("/", "meta-data", "testpath"),
|
||||
}
|
||||
|
||||
req := c.NewRequest(op, nil, nil)
|
||||
assert.Equal(t, "http://169.254.169.254/latest", req.ClientInfo.Endpoint)
|
||||
assert.Equal(t, "http://169.254.169.254/latest/meta-data/testpath", req.HTTPRequest.URL.String())
|
||||
}
|
||||
|
||||
func TestGetMetadata(t *testing.T) {
|
||||
server := initTestServer(
|
||||
"/latest/meta-data/some/path",
|
||||
"success", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
resp, err := c.GetMetadata("some/path")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "success", resp)
|
||||
}
|
||||
|
||||
func TestGetRegion(t *testing.T) {
|
||||
server := initTestServer(
|
||||
"/latest/meta-data/placement/availability-zone",
|
||||
"us-west-2a", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
region, err := c.Region()
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "us-west-2", region)
|
||||
}
|
||||
|
||||
func TestMetadataAvailable(t *testing.T) {
|
||||
server := initTestServer(
|
||||
"/latest/meta-data/instance-id",
|
||||
"instance-id",
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
available := c.Available()
|
||||
|
||||
assert.True(t, available)
|
||||
}
|
||||
|
||||
func TestMetadataNotAvailable(t *testing.T) {
|
||||
c := ec2metadata.New(session.New())
|
||||
c.Handlers.Send.Clear()
|
||||
c.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: int(0),
|
||||
Status: http.StatusText(int(0)),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
r.Error = awserr.New("RequestError", "send request failed", nil)
|
||||
r.Retryable = aws.Bool(true) // network errors are retryable
|
||||
})
|
||||
|
||||
available := c.Available()
|
||||
|
||||
assert.False(t, available)
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// Package ec2metadata provides the client for making API calls to the
|
||||
// EC2 Metadata service.
|
||||
package ec2metadata
|
||||
|
||||
import (
|
||||
|
@ -8,89 +10,41 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
)
|
||||
|
||||
// DefaultRetries states the default number of times the service client will
|
||||
// attempt to retry a failed request before failing.
|
||||
const DefaultRetries = 3
|
||||
// ServiceName is the name of the service.
|
||||
const ServiceName = "ec2metadata"
|
||||
|
||||
// A Config provides the configuration for the EC2 Metadata service.
|
||||
type Config struct {
|
||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||
// that overrides the default service endpoint for a client. Set this
|
||||
// to nil, or `""` to use the default service endpoint.
|
||||
Endpoint *string
|
||||
|
||||
// The HTTP client to use when sending requests. Defaults to
|
||||
// `http.DefaultClient`.
|
||||
HTTPClient *http.Client
|
||||
|
||||
// An integer value representing the logging level. The default log level
|
||||
// is zero (LogOff), which represents no logging. To enable logging set
|
||||
// to a LogLevel Value.
|
||||
Logger aws.Logger
|
||||
|
||||
// The logger writer interface to write logging messages to. Defaults to
|
||||
// standard out.
|
||||
LogLevel *aws.LogLevelType
|
||||
|
||||
// The maximum number of times that a request will be retried for failures.
|
||||
// Defaults to DefaultRetries for the number of retries to be performed
|
||||
// per request.
|
||||
MaxRetries *int
|
||||
// A EC2Metadata is an EC2 Metadata service Client.
|
||||
type EC2Metadata struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// A Client is an EC2 Metadata service Client.
|
||||
type Client struct {
|
||||
*service.Service
|
||||
}
|
||||
|
||||
// New creates a new instance of the EC2 Metadata service client.
|
||||
// New creates a new instance of the EC2Metadata client with a session.
|
||||
// This client is safe to use across multiple goroutines.
|
||||
//
|
||||
// In the general use case the configuration for this service client should not
|
||||
// be needed and `nil` can be provided. Configuration is only needed if the
|
||||
// `ec2metadata.Config` defaults need to be overridden. Eg. Setting LogLevel.
|
||||
// Example:
|
||||
// // Create a EC2Metadata client from just a session.
|
||||
// svc := ec2metadata.New(mySession)
|
||||
//
|
||||
// @note This configuration will NOT be merged with the default AWS service
|
||||
// client configuration `defaults.DefaultConfig`. Due to circular dependencies
|
||||
// with the defaults package and credentials EC2 Role Provider.
|
||||
func New(config *Config) *Client {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: copyConfig(config),
|
||||
ServiceName: "Client",
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
APIVersion: "latest",
|
||||
},
|
||||
}
|
||||
service.Initialize()
|
||||
service.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
service.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
service.Handlers.Validate.Clear()
|
||||
service.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
return &Client{service}
|
||||
// // Create a EC2Metadata client with additional configuration
|
||||
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
func copyConfig(config *Config) *aws.Config {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
c := &aws.Config{
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
Endpoint: config.Endpoint,
|
||||
HTTPClient: config.HTTPClient,
|
||||
Logger: config.Logger,
|
||||
LogLevel: config.LogLevel,
|
||||
MaxRetries: config.MaxRetries,
|
||||
}
|
||||
|
||||
if c.HTTPClient == nil {
|
||||
c.HTTPClient = &http.Client{
|
||||
// NewClient returns a new EC2Metadata client. Should be used to create
|
||||
// a client when not using a session. Generally using just New with a session
|
||||
// is preferred.
|
||||
func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
|
||||
// If the default http client is provided, replace it with a custom
|
||||
// client using default timeouts.
|
||||
if cfg.HTTPClient == http.DefaultClient {
|
||||
cfg.HTTPClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
|
@ -104,17 +58,30 @@ func copyConfig(config *Config) *aws.Config {
|
|||
},
|
||||
}
|
||||
}
|
||||
if c.Logger == nil {
|
||||
c.Logger = aws.NewDefaultLogger()
|
||||
}
|
||||
if c.LogLevel == nil {
|
||||
c.LogLevel = aws.LogLevel(aws.LogOff)
|
||||
}
|
||||
if c.MaxRetries == nil {
|
||||
c.MaxRetries = aws.Int(DefaultRetries)
|
||||
|
||||
svc := &EC2Metadata{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "latest",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
return c
|
||||
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
svc.Handlers.Validate.Clear()
|
||||
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
// Add additional options to the service config
|
||||
for _, option := range opts {
|
||||
option(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
type metadataOutput struct {
|
||||
|
@ -143,7 +110,7 @@ func unmarshalError(r *request.Request) {
|
|||
}
|
||||
|
||||
func validateEndpointHandler(r *request.Request) {
|
||||
if r.Service.Endpoint == "" {
|
||||
if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}
|
||||
|
|
47
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/handlers_test.go
generated
vendored
Normal file
47
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/handlers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package request_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func TestHandlerList(t *testing.T) {
|
||||
s := ""
|
||||
r := &request.Request{}
|
||||
l := request.HandlerList{}
|
||||
l.PushBack(func(r *request.Request) {
|
||||
s += "a"
|
||||
r.Data = s
|
||||
})
|
||||
l.Run(r)
|
||||
assert.Equal(t, "a", s)
|
||||
assert.Equal(t, "a", r.Data)
|
||||
}
|
||||
|
||||
func TestMultipleHandlers(t *testing.T) {
|
||||
r := &request.Request{}
|
||||
l := request.HandlerList{}
|
||||
l.PushBack(func(r *request.Request) { r.Data = nil })
|
||||
l.PushFront(func(r *request.Request) { r.Data = aws.Bool(true) })
|
||||
l.Run(r)
|
||||
if r.Data != nil {
|
||||
t.Error("Expected handler to execute")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamedHandlers(t *testing.T) {
|
||||
l := request.HandlerList{}
|
||||
named := request.NamedHandler{"Name", func(r *request.Request) {}}
|
||||
named2 := request.NamedHandler{"NotName", func(r *request.Request) {}}
|
||||
l.PushBackNamed(named)
|
||||
l.PushBackNamed(named)
|
||||
l.PushBackNamed(named2)
|
||||
l.PushBack(func(r *request.Request) {})
|
||||
assert.Equal(t, 4, l.Len())
|
||||
l.Remove(named)
|
||||
assert.Equal(t, 2, l.Len())
|
||||
}
|
|
@ -12,15 +12,16 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
)
|
||||
|
||||
// A Request is the service request to be made.
|
||||
type Request struct {
|
||||
Config aws.Config
|
||||
ClientInfo metadata.ClientInfo
|
||||
Handlers Handlers
|
||||
|
||||
Retryer
|
||||
Service serviceinfo.ServiceInfo
|
||||
Handlers Handlers
|
||||
Time time.Time
|
||||
ExpireTime time.Duration
|
||||
Operation *Operation
|
||||
|
@ -32,7 +33,7 @@ type Request struct {
|
|||
Error error
|
||||
Data interface{}
|
||||
RequestID string
|
||||
RetryCount uint
|
||||
RetryCount int
|
||||
Retryable *bool
|
||||
RetryDelay time.Duration
|
||||
|
||||
|
@ -61,7 +62,9 @@ type Paginator struct {
|
|||
// Params is any value of input parameters to be the request payload.
|
||||
// Data is pointer value to an object which the request's response
|
||||
// payload will be deserialized to.
|
||||
func New(service serviceinfo.ServiceInfo, handlers Handlers, retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
||||
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||
|
||||
method := operation.HTTPMethod
|
||||
if method == "" {
|
||||
method = "POST"
|
||||
|
@ -72,12 +75,14 @@ func New(service serviceinfo.ServiceInfo, handlers Handlers, retryer Retryer, op
|
|||
}
|
||||
|
||||
httpReq, _ := http.NewRequest(method, "", nil)
|
||||
httpReq.URL, _ = url.Parse(service.Endpoint + p)
|
||||
httpReq.URL, _ = url.Parse(clientInfo.Endpoint + p)
|
||||
|
||||
r := &Request{
|
||||
Config: cfg,
|
||||
ClientInfo: clientInfo,
|
||||
Handlers: handlers.Copy(),
|
||||
|
||||
Retryer: retryer,
|
||||
Service: service,
|
||||
Handlers: handlers.Copy(),
|
||||
Time: time.Now(),
|
||||
ExpireTime: 0,
|
||||
Operation: operation,
|
||||
|
@ -140,7 +145,7 @@ func (r *Request) Presign(expireTime time.Duration) (string, error) {
|
|||
}
|
||||
|
||||
func debugLogReqError(r *Request, stage string, retrying bool, err error) {
|
||||
if !r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||
if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -149,8 +154,8 @@ func debugLogReqError(r *Request, stage string, retrying bool, err error) {
|
|||
retryStr = "will retry"
|
||||
}
|
||||
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
|
||||
stage, r.Service.ServiceName, r.Operation.Name, retryStr, err))
|
||||
r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
|
||||
stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err))
|
||||
}
|
||||
|
||||
// Build will build the request's object so it can be signed and sent
|
||||
|
@ -205,9 +210,9 @@ func (r *Request) Send() error {
|
|||
}
|
||||
|
||||
if aws.BoolValue(r.Retryable) {
|
||||
if r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
|
||||
r.Service.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
|
||||
r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
}
|
||||
|
||||
// Re-seek the body back to the original point in for a retry so that
|
||||
|
@ -263,86 +268,3 @@ func (r *Request) Send() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasNextPage returns true if this request has more pages of data available.
|
||||
func (r *Request) HasNextPage() bool {
|
||||
return r.nextPageTokens() != nil
|
||||
}
|
||||
|
||||
// nextPageTokens returns the tokens to use when asking for the next page of
|
||||
// data.
|
||||
func (r *Request) nextPageTokens() []interface{} {
|
||||
if r.Operation.Paginator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Operation.TruncationToken != "" {
|
||||
tr := awsutil.ValuesAtAnyPath(r.Data, r.Operation.TruncationToken)
|
||||
if tr == nil || len(tr) == 0 {
|
||||
return nil
|
||||
}
|
||||
switch v := tr[0].(type) {
|
||||
case bool:
|
||||
if v == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found := false
|
||||
tokens := make([]interface{}, len(r.Operation.OutputTokens))
|
||||
|
||||
for i, outtok := range r.Operation.OutputTokens {
|
||||
v := awsutil.ValuesAtAnyPath(r.Data, outtok)
|
||||
if v != nil && len(v) > 0 {
|
||||
found = true
|
||||
tokens[i] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
return tokens
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextPage returns a new Request that can be executed to return the next
|
||||
// page of result data. Call .Send() on this request to execute it.
|
||||
func (r *Request) NextPage() *Request {
|
||||
tokens := r.nextPageTokens()
|
||||
if tokens == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
|
||||
nr := New(r.Service, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
|
||||
for i, intok := range nr.Operation.InputTokens {
|
||||
awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
|
||||
}
|
||||
return nr
|
||||
}
|
||||
|
||||
// EachPage iterates over each page of a paginated request object. The fn
|
||||
// parameter should be a function with the following sample signature:
|
||||
//
|
||||
// func(page *T, lastPage bool) bool {
|
||||
// return true // return false to stop iterating
|
||||
// }
|
||||
//
|
||||
// Where "T" is the structure type matching the output structure of the given
|
||||
// operation. For example, a request object generated by
|
||||
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
|
||||
// as the structure "T". The lastPage value represents whether the page is
|
||||
// the last page of data or not. The return value of this function should
|
||||
// return true to keep iterating or false to stop.
|
||||
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||
for page := r; page != nil; page = page.NextPage() {
|
||||
page.Send()
|
||||
shouldContinue := fn(page.Data, !page.HasNextPage())
|
||||
if page.Error != nil || !shouldContinue {
|
||||
return page.Error
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
96
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
96
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
//type Paginater interface {
|
||||
// HasNextPage() bool
|
||||
// NextPage() *Request
|
||||
// EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error
|
||||
//}
|
||||
|
||||
// HasNextPage returns true if this request has more pages of data available.
|
||||
func (r *Request) HasNextPage() bool {
|
||||
return r.nextPageTokens() != nil
|
||||
}
|
||||
|
||||
// nextPageTokens returns the tokens to use when asking for the next page of
|
||||
// data.
|
||||
func (r *Request) nextPageTokens() []interface{} {
|
||||
if r.Operation.Paginator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Operation.TruncationToken != "" {
|
||||
tr := awsutil.ValuesAtAnyPath(r.Data, r.Operation.TruncationToken)
|
||||
if tr == nil || len(tr) == 0 {
|
||||
return nil
|
||||
}
|
||||
switch v := tr[0].(type) {
|
||||
case bool:
|
||||
if v == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found := false
|
||||
tokens := make([]interface{}, len(r.Operation.OutputTokens))
|
||||
|
||||
for i, outToken := range r.Operation.OutputTokens {
|
||||
v := awsutil.ValuesAtAnyPath(r.Data, outToken)
|
||||
if v != nil && len(v) > 0 {
|
||||
found = true
|
||||
tokens[i] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
return tokens
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextPage returns a new Request that can be executed to return the next
|
||||
// page of result data. Call .Send() on this request to execute it.
|
||||
func (r *Request) NextPage() *Request {
|
||||
tokens := r.nextPageTokens()
|
||||
if tokens == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
|
||||
nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
|
||||
for i, intok := range nr.Operation.InputTokens {
|
||||
awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
|
||||
}
|
||||
return nr
|
||||
}
|
||||
|
||||
// EachPage iterates over each page of a paginated request object. The fn
|
||||
// parameter should be a function with the following sample signature:
|
||||
//
|
||||
// func(page *T, lastPage bool) bool {
|
||||
// return true // return false to stop iterating
|
||||
// }
|
||||
//
|
||||
// Where "T" is the structure type matching the output structure of the given
|
||||
// operation. For example, a request object generated by
|
||||
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
|
||||
// as the structure "T". The lastPage value represents whether the page is
|
||||
// the last page of data or not. The return value of this function should
|
||||
// return true to keep iterating or false to stop.
|
||||
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||
for page := r; page != nil; page = page.NextPage() {
|
||||
page.Send()
|
||||
shouldContinue := fn(page.Data, !page.HasNextPage())
|
||||
if page.Error != nil || !shouldContinue {
|
||||
return page.Error
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
305
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go
generated
vendored
Normal file
305
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go
generated
vendored
Normal file
|
@ -0,0 +1,305 @@
|
|||
package request_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPagination(t *testing.T) {
|
||||
db := dynamodb.New(unit.Session)
|
||||
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
|
||||
|
||||
reqNum := 0
|
||||
resps := []*dynamodb.ListTablesOutput{
|
||||
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
|
||||
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
|
||||
{TableNames: []*string{aws.String("Table5")}},
|
||||
}
|
||||
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
db.Handlers.ValidateResponse.Clear()
|
||||
db.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
in := r.Params.(*dynamodb.ListTablesInput)
|
||||
if in == nil {
|
||||
tokens = append(tokens, "")
|
||||
} else if in.ExclusiveStartTableName != nil {
|
||||
tokens = append(tokens, *in.ExclusiveStartTableName)
|
||||
}
|
||||
})
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
|
||||
err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
|
||||
numPages++
|
||||
for _, t := range p.TableNames {
|
||||
pages = append(pages, *t)
|
||||
}
|
||||
if last {
|
||||
if gotToEnd {
|
||||
assert.Fail(t, "last=true happened twice")
|
||||
}
|
||||
gotToEnd = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, []string{"Table2", "Table4"}, tokens)
|
||||
assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages)
|
||||
assert.Equal(t, 3, numPages)
|
||||
assert.True(t, gotToEnd)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, params.ExclusiveStartTableName)
|
||||
}
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPaginationEachPage(t *testing.T) {
|
||||
db := dynamodb.New(unit.Session)
|
||||
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
|
||||
|
||||
reqNum := 0
|
||||
resps := []*dynamodb.ListTablesOutput{
|
||||
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
|
||||
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
|
||||
{TableNames: []*string{aws.String("Table5")}},
|
||||
}
|
||||
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
db.Handlers.ValidateResponse.Clear()
|
||||
db.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
in := r.Params.(*dynamodb.ListTablesInput)
|
||||
if in == nil {
|
||||
tokens = append(tokens, "")
|
||||
} else if in.ExclusiveStartTableName != nil {
|
||||
tokens = append(tokens, *in.ExclusiveStartTableName)
|
||||
}
|
||||
})
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
|
||||
req, _ := db.ListTablesRequest(params)
|
||||
err := req.EachPage(func(p interface{}, last bool) bool {
|
||||
numPages++
|
||||
for _, t := range p.(*dynamodb.ListTablesOutput).TableNames {
|
||||
pages = append(pages, *t)
|
||||
}
|
||||
if last {
|
||||
if gotToEnd {
|
||||
assert.Fail(t, "last=true happened twice")
|
||||
}
|
||||
gotToEnd = true
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, []string{"Table2", "Table4"}, tokens)
|
||||
assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages)
|
||||
assert.Equal(t, 3, numPages)
|
||||
assert.True(t, gotToEnd)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPaginationEarlyExit(t *testing.T) {
|
||||
db := dynamodb.New(unit.Session)
|
||||
numPages, gotToEnd := 0, false
|
||||
|
||||
reqNum := 0
|
||||
resps := []*dynamodb.ListTablesOutput{
|
||||
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
|
||||
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
|
||||
{TableNames: []*string{aws.String("Table5")}},
|
||||
}
|
||||
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
db.Handlers.ValidateResponse.Clear()
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
|
||||
err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
|
||||
numPages++
|
||||
if numPages == 2 {
|
||||
return false
|
||||
}
|
||||
if last {
|
||||
if gotToEnd {
|
||||
assert.Fail(t, "last=true happened twice")
|
||||
}
|
||||
gotToEnd = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, 2, numPages)
|
||||
assert.False(t, gotToEnd)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSkipPagination(t *testing.T) {
|
||||
client := s3.New(unit.Session)
|
||||
client.Handlers.Send.Clear() // mock sending
|
||||
client.Handlers.Unmarshal.Clear()
|
||||
client.Handlers.UnmarshalMeta.Clear()
|
||||
client.Handlers.ValidateResponse.Clear()
|
||||
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = &s3.HeadBucketOutput{}
|
||||
})
|
||||
|
||||
req, _ := client.HeadBucketRequest(&s3.HeadBucketInput{Bucket: aws.String("bucket")})
|
||||
|
||||
numPages, gotToEnd := 0, false
|
||||
req.EachPage(func(p interface{}, last bool) bool {
|
||||
numPages++
|
||||
if last {
|
||||
gotToEnd = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
assert.Equal(t, 1, numPages)
|
||||
assert.True(t, gotToEnd)
|
||||
}
|
||||
|
||||
// Use S3 for simplicity
|
||||
func TestPaginationTruncation(t *testing.T) {
|
||||
count := 0
|
||||
client := s3.New(unit.Session)
|
||||
|
||||
reqNum := &count
|
||||
resps := []*s3.ListObjectsOutput{
|
||||
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}},
|
||||
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}},
|
||||
{IsTruncated: aws.Bool(false), Contents: []*s3.Object{{Key: aws.String("Key3")}}},
|
||||
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key4")}}},
|
||||
}
|
||||
|
||||
client.Handlers.Send.Clear() // mock sending
|
||||
client.Handlers.Unmarshal.Clear()
|
||||
client.Handlers.UnmarshalMeta.Clear()
|
||||
client.Handlers.ValidateResponse.Clear()
|
||||
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[*reqNum]
|
||||
*reqNum++
|
||||
})
|
||||
|
||||
params := &s3.ListObjectsInput{Bucket: aws.String("bucket")}
|
||||
|
||||
results := []string{}
|
||||
err := client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
|
||||
results = append(results, *p.Contents[0].Key)
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, []string{"Key1", "Key2", "Key3"}, results)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Try again without truncation token at all
|
||||
count = 0
|
||||
resps[1].IsTruncated = nil
|
||||
resps[2].IsTruncated = aws.Bool(true)
|
||||
results = []string{}
|
||||
err = client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
|
||||
results = append(results, *p.Contents[0].Key)
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, []string{"Key1", "Key2"}, results)
|
||||
assert.Nil(t, err)
|
||||
|
||||
}
|
||||
|
||||
// Benchmarks
|
||||
var benchResps = []*dynamodb.ListTablesOutput{
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
|
||||
{TableNames: []*string{aws.String("TABLE")}},
|
||||
}
|
||||
|
||||
var benchDb = func() *dynamodb.DynamoDB {
|
||||
db := dynamodb.New(unit.Session)
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
db.Handlers.ValidateResponse.Clear()
|
||||
return db
|
||||
}
|
||||
|
||||
func BenchmarkCodegenIterator(b *testing.B) {
|
||||
reqNum := 0
|
||||
db := benchDb()
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = benchResps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
|
||||
iter := func(fn func(*dynamodb.ListTablesOutput, bool) bool) error {
|
||||
page, _ := db.ListTablesRequest(input)
|
||||
for ; page != nil; page = page.NextPage() {
|
||||
page.Send()
|
||||
out := page.Data.(*dynamodb.ListTablesOutput)
|
||||
if result := fn(out, !page.HasNextPage()); page.Error != nil || !result {
|
||||
return page.Error
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
reqNum = 0
|
||||
iter(func(p *dynamodb.ListTablesOutput, last bool) bool {
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEachPageIterator(b *testing.B) {
|
||||
reqNum := 0
|
||||
db := benchDb()
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = benchResps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
|
||||
for i := 0; i < b.N; i++ {
|
||||
reqNum = 0
|
||||
req, _ := db.ListTablesRequest(input)
|
||||
req.EachPage(func(p interface{}, last bool) bool {
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
229
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_test.go
generated
vendored
Normal file
229
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/request/request_test.go
generated
vendored
Normal file
|
@ -0,0 +1,229 @@
|
|||
package request_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awstesting"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
type testData struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
func body(str string) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(str)))
|
||||
}
|
||||
|
||||
func unmarshal(req *request.Request) {
|
||||
defer req.HTTPResponse.Body.Close()
|
||||
if req.Data != nil {
|
||||
json.NewDecoder(req.HTTPResponse.Body).Decode(req.Data)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unmarshalError(req *request.Request) {
|
||||
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
req.Error = awserr.New("UnmarshaleError", req.HTTPResponse.Status, err)
|
||||
return
|
||||
}
|
||||
if len(bodyBytes) == 0 {
|
||||
req.Error = awserr.NewRequestFailure(
|
||||
awserr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")),
|
||||
req.HTTPResponse.StatusCode,
|
||||
"",
|
||||
)
|
||||
return
|
||||
}
|
||||
var jsonErr jsonErrorResponse
|
||||
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
|
||||
req.Error = awserr.New("UnmarshaleError", "JSON unmarshal", err)
|
||||
return
|
||||
}
|
||||
req.Error = awserr.NewRequestFailure(
|
||||
awserr.New(jsonErr.Code, jsonErr.Message, nil),
|
||||
req.HTTPResponse.StatusCode,
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
type jsonErrorResponse struct {
|
||||
Code string `json:"__type"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// test that retries occur for 5xx status codes
|
||||
func TestRequestRecoverRetry5xx(t *testing.T) {
|
||||
reqNum := 0
|
||||
reqs := []http.Response{
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
{StatusCode: 501, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &reqs[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
out := &testData{}
|
||||
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
|
||||
err := r.Send()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, int(r.RetryCount))
|
||||
assert.Equal(t, "valid", out.Data)
|
||||
}
|
||||
|
||||
// test that retries occur for 4xx status codes with a response type that can be retried - see `shouldRetry`
|
||||
func TestRequestRecoverRetry4xxRetryable(t *testing.T) {
|
||||
reqNum := 0
|
||||
reqs := []http.Response{
|
||||
{StatusCode: 400, Body: body(`{"__type":"Throttling","message":"Rate exceeded."}`)},
|
||||
{StatusCode: 429, Body: body(`{"__type":"ProvisionedThroughputExceededException","message":"Rate exceeded."}`)},
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &reqs[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
out := &testData{}
|
||||
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
|
||||
err := r.Send()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, int(r.RetryCount))
|
||||
assert.Equal(t, "valid", out.Data)
|
||||
}
|
||||
|
||||
// test that retries don't occur for 4xx status codes with a response type that can't be retried
|
||||
func TestRequest4xxUnretryable(t *testing.T) {
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &http.Response{StatusCode: 401, Body: body(`{"__type":"SignatureDoesNotMatch","message":"Signature does not match."}`)}
|
||||
})
|
||||
out := &testData{}
|
||||
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
|
||||
err := r.Send()
|
||||
assert.NotNil(t, err)
|
||||
if e, ok := err.(awserr.RequestFailure); ok {
|
||||
assert.Equal(t, 401, e.StatusCode())
|
||||
} else {
|
||||
assert.Fail(t, "Expected error to be a service failure")
|
||||
}
|
||||
assert.Equal(t, "SignatureDoesNotMatch", err.(awserr.Error).Code())
|
||||
assert.Equal(t, "Signature does not match.", err.(awserr.Error).Message())
|
||||
assert.Equal(t, 0, int(r.RetryCount))
|
||||
}
|
||||
|
||||
func TestRequestExhaustRetries(t *testing.T) {
|
||||
delays := []time.Duration{}
|
||||
sleepDelay := func(delay time.Duration) {
|
||||
delays = append(delays, delay)
|
||||
}
|
||||
|
||||
reqNum := 0
|
||||
reqs := []http.Response{
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
}
|
||||
|
||||
s := awstesting.NewClient(aws.NewConfig().WithSleepDelay(sleepDelay))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &reqs[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := r.Send()
|
||||
assert.NotNil(t, err)
|
||||
if e, ok := err.(awserr.RequestFailure); ok {
|
||||
assert.Equal(t, 500, e.StatusCode())
|
||||
} else {
|
||||
assert.Fail(t, "Expected error to be a service failure")
|
||||
}
|
||||
assert.Equal(t, "UnknownError", err.(awserr.Error).Code())
|
||||
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
|
||||
assert.Equal(t, 3, int(r.RetryCount))
|
||||
|
||||
expectDelays := []struct{ min, max time.Duration }{{30, 59}, {60, 118}, {120, 236}}
|
||||
for i, v := range delays {
|
||||
min := expectDelays[i].min * time.Millisecond
|
||||
max := expectDelays[i].max * time.Millisecond
|
||||
assert.True(t, min <= v && v <= max,
|
||||
"Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", i, v, min, max)
|
||||
}
|
||||
}
|
||||
|
||||
// test that the request is retried after the credentials are expired.
|
||||
func TestRequestRecoverExpiredCreds(t *testing.T) {
|
||||
reqNum := 0
|
||||
reqs := []http.Response{
|
||||
{StatusCode: 400, Body: body(`{"__type":"ExpiredTokenException","message":"expired token"}`)},
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := awstesting.NewClient(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")})
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
|
||||
credExpiredBeforeRetry := false
|
||||
credExpiredAfterRetry := false
|
||||
|
||||
s.Handlers.AfterRetry.PushBack(func(r *request.Request) {
|
||||
credExpiredAfterRetry = r.Config.Credentials.IsExpired()
|
||||
})
|
||||
|
||||
s.Handlers.Sign.Clear()
|
||||
s.Handlers.Sign.PushBack(func(r *request.Request) {
|
||||
r.Config.Credentials.Get()
|
||||
})
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &reqs[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
out := &testData{}
|
||||
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
|
||||
err := r.Send()
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.False(t, credExpiredBeforeRetry, "Expect valid creds before retry check")
|
||||
assert.True(t, credExpiredAfterRetry, "Expect expired creds after retry check")
|
||||
assert.False(t, s.Config.Credentials.IsExpired(), "Expect valid creds after cred expired recovery")
|
||||
|
||||
assert.Equal(t, 1, int(r.RetryCount))
|
||||
assert.Equal(t, "valid", out.Data)
|
||||
}
|
|
@ -12,13 +12,14 @@ import (
|
|||
type Retryer interface {
|
||||
RetryRules(*Request) time.Duration
|
||||
ShouldRetry(*Request) bool
|
||||
MaxRetries() uint
|
||||
MaxRetries() int
|
||||
}
|
||||
|
||||
// retryableCodes is a collection of service response codes which are retry-able
|
||||
// without any further action.
|
||||
var retryableCodes = map[string]struct{}{
|
||||
"RequestError": {},
|
||||
"RequestTimeout": {},
|
||||
"ProvisionedThroughputExceededException": {},
|
||||
"Throttling": {},
|
||||
"ThrottlingException": {},
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/internal/endpoints"
|
||||
)
|
||||
|
||||
// A Service implements the base service request and response handling
|
||||
// used by all services.
|
||||
type Service struct {
|
||||
serviceinfo.ServiceInfo
|
||||
request.Retryer
|
||||
DefaultMaxRetries uint
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// New will return a pointer to a new Server object initialized.
|
||||
func New(config *aws.Config) *Service {
|
||||
svc := &Service{ServiceInfo: serviceinfo.ServiceInfo{Config: config}}
|
||||
svc.Initialize()
|
||||
return svc
|
||||
}
|
||||
|
||||
// Initialize initializes the service.
|
||||
func (s *Service) Initialize() {
|
||||
if s.Config == nil {
|
||||
s.Config = &aws.Config{}
|
||||
}
|
||||
if s.Config.HTTPClient == nil {
|
||||
s.Config.HTTPClient = http.DefaultClient
|
||||
}
|
||||
if s.Config.SleepDelay == nil {
|
||||
s.Config.SleepDelay = time.Sleep
|
||||
}
|
||||
|
||||
s.Retryer = DefaultRetryer{s}
|
||||
s.DefaultMaxRetries = 3
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
s.Handlers.Build.PushBackNamed(corehandlers.UserAgentHandler)
|
||||
s.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
s.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
s.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
s.Handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
if !aws.BoolValue(s.Config.DisableParamValidation) {
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
|
||||
}
|
||||
s.AddDebugHandlers()
|
||||
s.buildEndpoint()
|
||||
}
|
||||
|
||||
// NewRequest returns a new Request pointer for the service API
|
||||
// operation and parameters.
|
||||
func (s *Service) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||
return request.New(s.ServiceInfo, s.Handlers, s.Retryer, operation, params, data)
|
||||
}
|
||||
|
||||
// buildEndpoint builds the endpoint values the service will use to make requests with.
|
||||
func (s *Service) buildEndpoint() {
|
||||
if aws.StringValue(s.Config.Endpoint) != "" {
|
||||
s.Endpoint = *s.Config.Endpoint
|
||||
} else if s.Endpoint == "" {
|
||||
s.Endpoint, s.SigningRegion =
|
||||
endpoints.EndpointForRegion(s.ServiceName, aws.StringValue(s.Config.Region))
|
||||
}
|
||||
|
||||
if s.Endpoint != "" && !schemeRE.MatchString(s.Endpoint) {
|
||||
scheme := "https"
|
||||
if aws.BoolValue(s.Config.DisableSSL) {
|
||||
scheme = "http"
|
||||
}
|
||||
s.Endpoint = scheme + "://" + s.Endpoint
|
||||
}
|
||||
}
|
||||
|
||||
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||
// debug information.
|
||||
func (s *Service) AddDebugHandlers() {
|
||||
if !s.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||
return
|
||||
}
|
||||
|
||||
s.Handlers.Send.PushFront(logRequest)
|
||||
s.Handlers.Send.PushBack(logResponse)
|
||||
}
|
||||
|
||||
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||
---[ REQUEST POST-SIGN ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.Service.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
---[ RESPONSE ]--------------------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no reponse data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
}
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.Service.ServiceName, r.Operation.Name, msg))
|
||||
}
|
15
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/service/serviceinfo/service_info.go
generated
vendored
15
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/service/serviceinfo/service_info.go
generated
vendored
|
@ -1,15 +0,0 @@
|
|||
package serviceinfo
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
// ServiceInfo wraps immutable data from the service.Service structure.
|
||||
type ServiceInfo struct {
|
||||
Config *aws.Config
|
||||
ServiceName string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
SigningRegion string
|
||||
JSONVersion string
|
||||
TargetPrefix string
|
||||
}
|
105
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
Normal file
105
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Package session provides a way to create service clients with shared configuration
|
||||
// and handlers.
|
||||
package session
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// A Session provides a central location to create service clients from and
|
||||
// store configurations and request handlers for those services.
|
||||
//
|
||||
// Sessions are safe to create service clients concurrently, but it is not safe
|
||||
// to mutate the session concurrently.
|
||||
type Session struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New creates a new instance of the handlers merging in the provided Configs
|
||||
// on top of the SDK's default configurations. Once the session is created it
|
||||
// can be mutated to modify Configs or Handlers. The session is safe to be read
|
||||
// concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// Example:
|
||||
// // Create a session with the default config and request handlers.
|
||||
// sess := session.New()
|
||||
//
|
||||
// // Create a session with a custom region
|
||||
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
|
||||
//
|
||||
// // Create a session, and add additional handlers for all service
|
||||
// // clients created with the session to inherit. Adds logging handler.
|
||||
// sess := session.New()
|
||||
// sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// // Log every request made and its payload
|
||||
// logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
// })
|
||||
//
|
||||
// // Create a S3 client instance from a session
|
||||
// sess := session.New()
|
||||
// svc := s3.New(sess)
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
def := defaults.Get()
|
||||
s := &Session{
|
||||
Config: def.Config,
|
||||
Handlers: def.Handlers,
|
||||
}
|
||||
s.Config.MergeIn(cfgs...)
|
||||
|
||||
initHandlers(s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func initHandlers(s *Session) {
|
||||
// Add the Validate parameter handler if it is not disabled.
|
||||
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||
if !aws.BoolValue(s.Config.DisableParamValidation) {
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates and returns a copy of the current session, coping the config
|
||||
// and handlers. If any additional configs are provided they will be merged
|
||||
// on top of the session's copied config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a copy of the current session, configured for the us-west-2 region.
|
||||
// sess.Copy(&aws.Config{Region: aws.String("us-west-2"})
|
||||
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||
newSession := &Session{
|
||||
Config: s.Config.Copy(cfgs...),
|
||||
Handlers: s.Handlers.Copy(),
|
||||
}
|
||||
|
||||
initHandlers(newSession)
|
||||
|
||||
return newSession
|
||||
}
|
||||
|
||||
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||
// configure the service client instances. Passing the Session to the service
|
||||
// client's constructor (New) will use this method to configure the client.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New()
|
||||
// s3.New(sess)
|
||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||
s = s.Copy(cfgs...)
|
||||
endpoint, signingRegion := endpoints.NormalizeEndpoint(
|
||||
aws.StringValue(s.Config.Endpoint), serviceName,
|
||||
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
Handlers: s.Handlers,
|
||||
Endpoint: endpoint,
|
||||
SigningRegion: signingRegion,
|
||||
}
|
||||
}
|
20
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session/session_test.go
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session/session_test.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
package session_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
func TestNewDefaultSession(t *testing.T) {
|
||||
s := session.New(&aws.Config{Region: aws.String("region")})
|
||||
|
||||
assert.Equal(t, "region", *s.Config.Region)
|
||||
assert.Equal(t, http.DefaultClient, s.Config.HTTPClient)
|
||||
assert.NotNil(t, s.Config.Logger)
|
||||
assert.Equal(t, aws.LogOff, *s.Config.LogLevel)
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeakerCloser
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser
|
||||
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
|
||||
return ReaderSeekerCloser{r}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriteAtBuffer(t *testing.T) {
|
||||
b := &WriteAtBuffer{}
|
||||
|
||||
n, err := b.WriteAt([]byte{1}, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, n)
|
||||
|
||||
n, err = b.WriteAt([]byte{1, 1, 1}, 5)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, n)
|
||||
|
||||
n, err = b.WriteAt([]byte{2}, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, n)
|
||||
|
||||
n, err = b.WriteAt([]byte{3}, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, n)
|
||||
|
||||
assert.Equal(t, []byte{1, 2, 3, 0, 0, 1, 1, 1}, b.Bytes())
|
||||
}
|
||||
|
||||
func BenchmarkWriteAtBuffer(b *testing.B) {
|
||||
buf := &WriteAtBuffer{}
|
||||
r := rand.New(rand.NewSource(1))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
to := r.Intn(10) * 4096
|
||||
bs := make([]byte, to)
|
||||
buf.WriteAt(bs, r.Int63n(10)*4096)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWriteAtBufferParallel(b *testing.B) {
|
||||
buf := &WriteAtBuffer{}
|
||||
r := rand.New(rand.NewSource(1))
|
||||
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
to := r.Intn(10) * 4096
|
||||
bs := make([]byte, to)
|
||||
buf.WriteAt(bs, r.Int63n(10)*4096)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "0.9.16"
|
||||
const SDKVersion = "release-v0.10.0"
|
||||
|
|
31
Godeps/_workspace/src/github.com/aws/aws-sdk-go/internal/endpoints/endpoints.go
generated
vendored
31
Godeps/_workspace/src/github.com/aws/aws-sdk-go/internal/endpoints/endpoints.go
generated
vendored
|
@ -1,31 +0,0 @@
|
|||
// Package endpoints validates regional endpoints for services.
|
||||
package endpoints
|
||||
|
||||
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate gofmt -s -w endpoints_map.go
|
||||
|
||||
import "strings"
|
||||
|
||||
// EndpointForRegion returns an endpoint and its signing region for a service and region.
|
||||
// if the service and region pair are not found endpoint and signingRegion will be empty.
|
||||
func EndpointForRegion(svcName, region string) (endpoint, signingRegion string) {
|
||||
derivedKeys := []string{
|
||||
region + "/" + svcName,
|
||||
region + "/*",
|
||||
"*/" + svcName,
|
||||
"*/*",
|
||||
}
|
||||
|
||||
for _, key := range derivedKeys {
|
||||
if val, ok := endpointsMap.Endpoints[key]; ok {
|
||||
ep := val.Endpoint
|
||||
ep = strings.Replace(ep, "{region}", region, -1)
|
||||
ep = strings.Replace(ep, "{service}", svcName, -1)
|
||||
|
||||
endpoint = ep
|
||||
signingRegion = val.SigningRegion
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
65
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/endpoints/endpoints.go
generated
vendored
Normal file
65
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/endpoints/endpoints.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Package endpoints validates regional endpoints for services.
|
||||
package endpoints
|
||||
|
||||
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate gofmt -s -w endpoints_map.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NormalizeEndpoint takes and endpoint and service API information to return a
|
||||
// normalized endpoint and signing region. If the endpoint is not an empty string
|
||||
// the service name and region will be used to look up the service's API endpoint.
|
||||
// If the endpoint is provided the scheme will be added if it is not present.
|
||||
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (normEndpoint, signingRegion string) {
|
||||
if endpoint == "" {
|
||||
return EndpointForRegion(serviceName, region, disableSSL)
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), ""
|
||||
}
|
||||
|
||||
// EndpointForRegion returns an endpoint and its signing region for a service and region.
|
||||
// if the service and region pair are not found endpoint and signingRegion will be empty.
|
||||
func EndpointForRegion(svcName, region string, disableSSL bool) (endpoint, signingRegion string) {
|
||||
derivedKeys := []string{
|
||||
region + "/" + svcName,
|
||||
region + "/*",
|
||||
"*/" + svcName,
|
||||
"*/*",
|
||||
}
|
||||
|
||||
for _, key := range derivedKeys {
|
||||
if val, ok := endpointsMap.Endpoints[key]; ok {
|
||||
ep := val.Endpoint
|
||||
ep = strings.Replace(ep, "{region}", region, -1)
|
||||
ep = strings.Replace(ep, "{service}", svcName, -1)
|
||||
|
||||
endpoint = ep
|
||||
signingRegion = val.SigningRegion
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), signingRegion
|
||||
}
|
||||
|
||||
// Regular expression to determine if the endpoint string is prefixed with a scheme.
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||
// scheme. If disableSSL is true HTTP will be added instead of the default HTTPS.
|
||||
func AddScheme(endpoint string, disableSSL bool) string {
|
||||
if endpoint != "" && !schemeRE.MatchString(endpoint) {
|
||||
scheme := "https"
|
||||
if disableSSL {
|
||||
scheme = "http"
|
||||
}
|
||||
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
|
@ -29,6 +29,10 @@
|
|||
"endpoint": "",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/iam": {
|
||||
"endpoint": "iam.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
|
@ -45,6 +49,10 @@
|
|||
"endpoint": "sts.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/waf": {
|
||||
"endpoint": "waf.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"us-east-1/sdb": {
|
||||
"endpoint": "sdb.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
|
@ -30,6 +30,10 @@ var endpointsMap = endpointStruct{
|
|||
Endpoint: "",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/iam": {
|
||||
Endpoint: "iam.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
|
@ -46,6 +50,10 @@ var endpointsMap = endpointStruct{
|
|||
Endpoint: "sts.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/waf": {
|
||||
Endpoint: "waf.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"ap-northeast-1/s3": {
|
||||
Endpoint: "s3-{region}.amazonaws.com",
|
||||
},
|
41
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/endpoints/endpoints_test.go
generated
vendored
Normal file
41
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/endpoints/endpoints_test.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
package endpoints_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
func TestGenericEndpoint(t *testing.T) {
|
||||
name := "service"
|
||||
region := "mock-region-1"
|
||||
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.%s.amazonaws.com", name, region), ep)
|
||||
assert.Empty(t, sr)
|
||||
}
|
||||
|
||||
func TestGlobalEndpoints(t *testing.T) {
|
||||
region := "mock-region-1"
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "waf"}
|
||||
|
||||
for _, name := range svcs {
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.amazonaws.com", name), ep)
|
||||
assert.Equal(t, "us-east-1", sr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicesInCN(t *testing.T) {
|
||||
region := "cn-north-1"
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "s3", "waf"}
|
||||
|
||||
for _, name := range svcs {
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.%s.amazonaws.com.cn", name, region), ep)
|
||||
assert.Empty(t, sr)
|
||||
}
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
// Package ec2query provides serialisation of AWS EC2 requests and responses.
|
||||
package ec2query
|
||||
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/ec2.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/ec2.json build_test.go
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query/queryutil"
|
||||
)
|
||||
|
||||
// Build builds a request for the EC2 protocol.
|
||||
func Build(r *request.Request) {
|
||||
body := url.Values{
|
||||
"Action": {r.Operation.Name},
|
||||
"Version": {r.Service.APIVersion},
|
||||
"Version": {r.ClientInfo.APIVersion},
|
||||
}
|
||||
if err := queryutil.Parse(body, r.Params, true); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
|
85
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go
generated
vendored
Normal file
85
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
// +build bench
|
||||
|
||||
package ec2query_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awstesting"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
)
|
||||
|
||||
func BenchmarkEC2QueryBuild_Complex_ec2AuthorizeSecurityGroupEgress(b *testing.B) {
|
||||
params := &ec2.AuthorizeSecurityGroupEgressInput{
|
||||
GroupId: aws.String("String"), // Required
|
||||
CidrIp: aws.String("String"),
|
||||
DryRun: aws.Bool(true),
|
||||
FromPort: aws.Int64(1),
|
||||
IpPermissions: []*ec2.IpPermission{
|
||||
{ // Required
|
||||
FromPort: aws.Int64(1),
|
||||
IpProtocol: aws.String("String"),
|
||||
IpRanges: []*ec2.IpRange{
|
||||
{ // Required
|
||||
CidrIp: aws.String("String"),
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
PrefixListIds: []*ec2.PrefixListId{
|
||||
{ // Required
|
||||
PrefixListId: aws.String("String"),
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
ToPort: aws.Int64(1),
|
||||
UserIdGroupPairs: []*ec2.UserIdGroupPair{
|
||||
{ // Required
|
||||
GroupId: aws.String("String"),
|
||||
GroupName: aws.String("String"),
|
||||
UserId: aws.String("String"),
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
IpProtocol: aws.String("String"),
|
||||
SourceSecurityGroupName: aws.String("String"),
|
||||
SourceSecurityGroupOwnerId: aws.String("String"),
|
||||
ToPort: aws.Int64(1),
|
||||
}
|
||||
|
||||
benchEC2QueryBuild(b, "AuthorizeSecurityGroupEgress", params)
|
||||
}
|
||||
|
||||
func BenchmarkEC2QueryBuild_Simple_ec2AttachNetworkInterface(b *testing.B) {
|
||||
params := &ec2.AttachNetworkInterfaceInput{
|
||||
DeviceIndex: aws.Int64(1), // Required
|
||||
InstanceId: aws.String("String"), // Required
|
||||
NetworkInterfaceId: aws.String("String"), // Required
|
||||
DryRun: aws.Bool(true),
|
||||
}
|
||||
|
||||
benchEC2QueryBuild(b, "AttachNetworkInterface", params)
|
||||
}
|
||||
|
||||
func benchEC2QueryBuild(b *testing.B, opName string, params interface{}) {
|
||||
svc := awstesting.NewClient()
|
||||
svc.ServiceName = "ec2"
|
||||
svc.APIVersion = "2015-04-15"
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
r := svc.NewRequest(&request.Operation{
|
||||
Name: opName,
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
}, params, nil)
|
||||
ec2query.Build(r)
|
||||
if r.Error != nil {
|
||||
b.Fatal("Unexpected error", r.Error)
|
||||
}
|
||||
}
|
||||
}
|
1051
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go
generated
vendored
Normal file
1051
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
package ec2query
|
||||
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/output/ec2.json unmarshal_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/ec2.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
)
|
||||
|
||||
// Unmarshal unmarshals a response body for the EC2 protocol.
|
1132
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go
generated
vendored
Normal file
1132
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +1,21 @@
|
|||
// Package query provides serialisation of AWS query requests, and responses.
|
||||
package query
|
||||
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/query.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query/queryutil"
|
||||
)
|
||||
|
||||
// Build builds a request for an AWS Query service.
|
||||
func Build(r *request.Request) {
|
||||
body := url.Values{
|
||||
"Action": {r.Operation.Name},
|
||||
"Version": {r.Service.APIVersion},
|
||||
"Version": {r.ClientInfo.APIVersion},
|
||||
}
|
||||
if err := queryutil.Parse(body, r.Params, false); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed encoding Query request", err)
|
2139
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go
generated
vendored
Normal file
2139
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +1,13 @@
|
|||
package query
|
||||
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/output/query.json unmarshal_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
)
|
||||
|
||||
// Unmarshal unmarshals a response for an AWS Query service.
|
1878
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go
generated
vendored
Normal file
1878
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
246
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/build_bench_test.go
generated
vendored
Normal file
246
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/build_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,246 @@
|
|||
// +build bench
|
||||
|
||||
package restxml_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awstesting"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/restxml"
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
)
|
||||
|
||||
func BenchmarkRESTXMLBuild_Complex_cloudfrontCreateDistribution(b *testing.B) {
|
||||
params := restxmlBuildCreateDistroParms
|
||||
|
||||
op := &request.Operation{
|
||||
Name: "CreateDistribution",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/2015-04-17/distribution/{DistributionId}/invalidation",
|
||||
}
|
||||
|
||||
benchRESTXMLBuild(b, op, params)
|
||||
}
|
||||
|
||||
func BenchmarkRESTXMLBuild_Simple_cloudfrontDeleteStreamingDistribution(b *testing.B) {
|
||||
params := &cloudfront.DeleteDistributionInput{
|
||||
Id: aws.String("string"), // Required
|
||||
IfMatch: aws.String("string"),
|
||||
}
|
||||
op := &request.Operation{
|
||||
Name: "DeleteStreamingDistribution",
|
||||
HTTPMethod: "DELETE",
|
||||
HTTPPath: "/2015-04-17/streaming-distribution/{Id}",
|
||||
}
|
||||
benchRESTXMLBuild(b, op, params)
|
||||
}
|
||||
|
||||
func BenchmarkEncodingXMLMarshal_Simple_cloudfrontDeleteStreamingDistribution(b *testing.B) {
|
||||
params := &cloudfront.DeleteDistributionInput{
|
||||
Id: aws.String("string"), // Required
|
||||
IfMatch: aws.String("string"),
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf := &bytes.Buffer{}
|
||||
encoder := xml.NewEncoder(buf)
|
||||
if err := encoder.Encode(params); err != nil {
|
||||
b.Fatal("Unexpected error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchRESTXMLBuild(b *testing.B, op *request.Operation, params interface{}) {
|
||||
svc := awstesting.NewClient()
|
||||
svc.ServiceName = "cloudfront"
|
||||
svc.APIVersion = "2015-04-17"
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
r := svc.NewRequest(op, params, nil)
|
||||
restxml.Build(r)
|
||||
if r.Error != nil {
|
||||
b.Fatal("Unexpected error", r.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var restxmlBuildCreateDistroParms = &cloudfront.CreateDistributionInput{
|
||||
DistributionConfig: &cloudfront.DistributionConfig{ // Required
|
||||
CallerReference: aws.String("string"), // Required
|
||||
Comment: aws.String("string"), // Required
|
||||
DefaultCacheBehavior: &cloudfront.DefaultCacheBehavior{ // Required
|
||||
ForwardedValues: &cloudfront.ForwardedValues{ // Required
|
||||
Cookies: &cloudfront.CookiePreference{ // Required
|
||||
Forward: aws.String("ItemSelection"), // Required
|
||||
WhitelistedNames: &cloudfront.CookieNames{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
},
|
||||
QueryString: aws.Bool(true), // Required
|
||||
Headers: &cloudfront.Headers{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
},
|
||||
MinTTL: aws.Int64(1), // Required
|
||||
TargetOriginId: aws.String("string"), // Required
|
||||
TrustedSigners: &cloudfront.TrustedSigners{ // Required
|
||||
Enabled: aws.Bool(true), // Required
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
ViewerProtocolPolicy: aws.String("ViewerProtocolPolicy"), // Required
|
||||
AllowedMethods: &cloudfront.AllowedMethods{
|
||||
Items: []*string{ // Required
|
||||
aws.String("Method"), // Required
|
||||
// More values...
|
||||
},
|
||||
Quantity: aws.Int64(1), // Required
|
||||
CachedMethods: &cloudfront.CachedMethods{
|
||||
Items: []*string{ // Required
|
||||
aws.String("Method"), // Required
|
||||
// More values...
|
||||
},
|
||||
Quantity: aws.Int64(1), // Required
|
||||
},
|
||||
},
|
||||
DefaultTTL: aws.Int64(1),
|
||||
MaxTTL: aws.Int64(1),
|
||||
SmoothStreaming: aws.Bool(true),
|
||||
},
|
||||
Enabled: aws.Bool(true), // Required
|
||||
Origins: &cloudfront.Origins{ // Required
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*cloudfront.Origin{
|
||||
{ // Required
|
||||
DomainName: aws.String("string"), // Required
|
||||
Id: aws.String("string"), // Required
|
||||
CustomOriginConfig: &cloudfront.CustomOriginConfig{
|
||||
HTTPPort: aws.Int64(1), // Required
|
||||
HTTPSPort: aws.Int64(1), // Required
|
||||
OriginProtocolPolicy: aws.String("OriginProtocolPolicy"), // Required
|
||||
},
|
||||
OriginPath: aws.String("string"),
|
||||
S3OriginConfig: &cloudfront.S3OriginConfig{
|
||||
OriginAccessIdentity: aws.String("string"), // Required
|
||||
},
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
Aliases: &cloudfront.Aliases{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
CacheBehaviors: &cloudfront.CacheBehaviors{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*cloudfront.CacheBehavior{
|
||||
{ // Required
|
||||
ForwardedValues: &cloudfront.ForwardedValues{ // Required
|
||||
Cookies: &cloudfront.CookiePreference{ // Required
|
||||
Forward: aws.String("ItemSelection"), // Required
|
||||
WhitelistedNames: &cloudfront.CookieNames{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
},
|
||||
QueryString: aws.Bool(true), // Required
|
||||
Headers: &cloudfront.Headers{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
},
|
||||
MinTTL: aws.Int64(1), // Required
|
||||
PathPattern: aws.String("string"), // Required
|
||||
TargetOriginId: aws.String("string"), // Required
|
||||
TrustedSigners: &cloudfront.TrustedSigners{ // Required
|
||||
Enabled: aws.Bool(true), // Required
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
ViewerProtocolPolicy: aws.String("ViewerProtocolPolicy"), // Required
|
||||
AllowedMethods: &cloudfront.AllowedMethods{
|
||||
Items: []*string{ // Required
|
||||
aws.String("Method"), // Required
|
||||
// More values...
|
||||
},
|
||||
Quantity: aws.Int64(1), // Required
|
||||
CachedMethods: &cloudfront.CachedMethods{
|
||||
Items: []*string{ // Required
|
||||
aws.String("Method"), // Required
|
||||
// More values...
|
||||
},
|
||||
Quantity: aws.Int64(1), // Required
|
||||
},
|
||||
},
|
||||
DefaultTTL: aws.Int64(1),
|
||||
MaxTTL: aws.Int64(1),
|
||||
SmoothStreaming: aws.Bool(true),
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
CustomErrorResponses: &cloudfront.CustomErrorResponses{
|
||||
Quantity: aws.Int64(1), // Required
|
||||
Items: []*cloudfront.CustomErrorResponse{
|
||||
{ // Required
|
||||
ErrorCode: aws.Int64(1), // Required
|
||||
ErrorCachingMinTTL: aws.Int64(1),
|
||||
ResponseCode: aws.String("string"),
|
||||
ResponsePagePath: aws.String("string"),
|
||||
},
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
DefaultRootObject: aws.String("string"),
|
||||
Logging: &cloudfront.LoggingConfig{
|
||||
Bucket: aws.String("string"), // Required
|
||||
Enabled: aws.Bool(true), // Required
|
||||
IncludeCookies: aws.Bool(true), // Required
|
||||
Prefix: aws.String("string"), // Required
|
||||
},
|
||||
PriceClass: aws.String("PriceClass"),
|
||||
Restrictions: &cloudfront.Restrictions{
|
||||
GeoRestriction: &cloudfront.GeoRestriction{ // Required
|
||||
Quantity: aws.Int64(1), // Required
|
||||
RestrictionType: aws.String("GeoRestrictionType"), // Required
|
||||
Items: []*string{
|
||||
aws.String("string"), // Required
|
||||
// More values...
|
||||
},
|
||||
},
|
||||
},
|
||||
ViewerCertificate: &cloudfront.ViewerCertificate{
|
||||
CloudFrontDefaultCertificate: aws.Bool(true),
|
||||
IAMCertificateId: aws.String("string"),
|
||||
MinimumProtocolVersion: aws.String("MinimumProtocolVersion"),
|
||||
SSLSupportMethod: aws.String("SSLSupportMethod"),
|
||||
},
|
||||
},
|
||||
}
|
3594
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/build_test.go
generated
vendored
Normal file
3594
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/build_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -2,8 +2,8 @@
|
|||
// requests and responses.
|
||||
package restxml
|
||||
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/rest-xml.json build_test.go
|
||||
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/output/rest-xml.json unmarshal_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -11,9 +11,9 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/rest"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/rest"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
)
|
||||
|
||||
// Build builds a request payload for the REST XML protocol.
|
1606
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/unmarshal_test.go
generated
vendored
Normal file
1606
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/restxml/unmarshal_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
42
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/signer/v4/functional_test.go
generated
vendored
Normal file
42
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/signer/v4/functional_test.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
package v4_test
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
func TestPresignHandler(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
ContentDisposition: aws.String("a+b c$d"),
|
||||
ACL: aws.String("public-read"),
|
||||
})
|
||||
req.Time = time.Unix(0, 0)
|
||||
urlstr, err := req.Presign(5 * time.Minute)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedDate := "19700101T000000Z"
|
||||
expectedHeaders := "host;x-amz-acl"
|
||||
expectedSig := "7edcb4e3a1bf12f4989018d75acbe3a7f03df24bd6f3112602d59fc551f0e4e2"
|
||||
expectedCred := "AKID/19700101/mock-region/s3/aws4_request"
|
||||
|
||||
u, _ := url.Parse(urlstr)
|
||||
urlQ := u.Query()
|
||||
assert.Equal(t, expectedSig, urlQ.Get("X-Amz-Signature"))
|
||||
assert.Equal(t, expectedCred, urlQ.Get("X-Amz-Credential"))
|
||||
assert.Equal(t, expectedHeaders, urlQ.Get("X-Amz-SignedHeaders"))
|
||||
assert.Equal(t, expectedDate, urlQ.Get("X-Amz-Date"))
|
||||
assert.Equal(t, "300", urlQ.Get("X-Amz-Expires"))
|
||||
|
||||
assert.NotContains(t, urlstr, "+") // + encoded as %20
|
||||
}
|
|
@ -17,7 +17,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/rest"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -67,18 +67,18 @@ type signer struct {
|
|||
func Sign(req *request.Request) {
|
||||
// If the request does not need to be signed ignore the signing of the
|
||||
// request if the AnonymousCredentials object is used.
|
||||
if req.Service.Config.Credentials == credentials.AnonymousCredentials {
|
||||
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
region := req.Service.SigningRegion
|
||||
region := req.ClientInfo.SigningRegion
|
||||
if region == "" {
|
||||
region = aws.StringValue(req.Service.Config.Region)
|
||||
region = aws.StringValue(req.Config.Region)
|
||||
}
|
||||
|
||||
name := req.Service.SigningName
|
||||
name := req.ClientInfo.SigningName
|
||||
if name == "" {
|
||||
name = req.Service.ServiceName
|
||||
name = req.ClientInfo.ServiceName
|
||||
}
|
||||
|
||||
s := signer{
|
||||
|
@ -89,9 +89,9 @@ func Sign(req *request.Request) {
|
|||
Body: req.Body,
|
||||
ServiceName: name,
|
||||
Region: region,
|
||||
Credentials: req.Service.Config.Credentials,
|
||||
Debug: req.Service.Config.LogLevel.Value(),
|
||||
Logger: req.Service.Config.Logger,
|
||||
Credentials: req.Config.Credentials,
|
||||
Debug: req.Config.LogLevel.Value(),
|
||||
Logger: req.Config.Logger,
|
||||
}
|
||||
|
||||
req.Error = s.sign()
|
248
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/signer/v4/v4_test.go
generated
vendored
Normal file
248
Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/signer/v4/v4_test.go
generated
vendored
Normal file
|
@ -0,0 +1,248 @@
|
|||
package v4
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awstesting"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func buildSigner(serviceName string, region string, signTime time.Time, expireTime time.Duration, body string) signer {
|
||||
endpoint := "https://" + serviceName + "." + region + ".amazonaws.com"
|
||||
reader := strings.NewReader(body)
|
||||
req, _ := http.NewRequest("POST", endpoint, reader)
|
||||
req.URL.Opaque = "//example.org/bucket/key-._~,!@#$%^&*()"
|
||||
req.Header.Add("X-Amz-Target", "prefix.Operation")
|
||||
req.Header.Add("Content-Type", "application/x-amz-json-1.0")
|
||||
req.Header.Add("Content-Length", string(len(body)))
|
||||
req.Header.Add("X-Amz-Meta-Other-Header", "some-value=!@#$%^&* (+)")
|
||||
|
||||
return signer{
|
||||
Request: req,
|
||||
Time: signTime,
|
||||
ExpireTime: expireTime,
|
||||
Query: req.URL.Query(),
|
||||
Body: reader,
|
||||
ServiceName: serviceName,
|
||||
Region: region,
|
||||
Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"),
|
||||
}
|
||||
}
|
||||
|
||||
func removeWS(text string) string {
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
text = strings.Replace(text, "\n", "", -1)
|
||||
text = strings.Replace(text, "\t", "", -1)
|
||||
return text
|
||||
}
|
||||
|
||||
func assertEqual(t *testing.T, expected, given string) {
|
||||
if removeWS(expected) != removeWS(given) {
|
||||
t.Errorf("\nExpected: %s\nGiven: %s", expected, given)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPresignRequest(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Unix(0, 0), 300*time.Second, "{}")
|
||||
signer.sign()
|
||||
|
||||
expectedDate := "19700101T000000Z"
|
||||
expectedHeaders := "host;x-amz-meta-other-header;x-amz-target"
|
||||
expectedSig := "5eeedebf6f995145ce56daa02902d10485246d3defb34f97b973c1f40ab82d36"
|
||||
expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request"
|
||||
|
||||
q := signer.Request.URL.Query()
|
||||
assert.Equal(t, expectedSig, q.Get("X-Amz-Signature"))
|
||||
assert.Equal(t, expectedCred, q.Get("X-Amz-Credential"))
|
||||
assert.Equal(t, expectedHeaders, q.Get("X-Amz-SignedHeaders"))
|
||||
assert.Equal(t, expectedDate, q.Get("X-Amz-Date"))
|
||||
}
|
||||
|
||||
func TestSignRequest(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Unix(0, 0), 0, "{}")
|
||||
signer.sign()
|
||||
|
||||
expectedDate := "19700101T000000Z"
|
||||
expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=host;x-amz-date;x-amz-meta-other-header;x-amz-security-token;x-amz-target, Signature=69ada33fec48180dab153576e4dd80c4e04124f80dda3eccfed8a67c2b91ed5e"
|
||||
|
||||
q := signer.Request.Header
|
||||
assert.Equal(t, expectedSig, q.Get("Authorization"))
|
||||
assert.Equal(t, expectedDate, q.Get("X-Amz-Date"))
|
||||
}
|
||||
|
||||
func TestSignEmptyBody(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 0, "")
|
||||
signer.Body = nil
|
||||
signer.sign()
|
||||
hash := signer.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hash)
|
||||
}
|
||||
|
||||
func TestSignBody(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 0, "hello")
|
||||
signer.sign()
|
||||
hash := signer.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash)
|
||||
}
|
||||
|
||||
func TestSignSeekedBody(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 0, " hello")
|
||||
signer.Body.Read(make([]byte, 3)) // consume first 3 bytes so body is now "hello"
|
||||
signer.sign()
|
||||
hash := signer.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash)
|
||||
|
||||
start, _ := signer.Body.Seek(0, 1)
|
||||
assert.Equal(t, int64(3), start)
|
||||
}
|
||||
|
||||
func TestPresignEmptyBodyS3(t *testing.T) {
|
||||
signer := buildSigner("s3", "us-east-1", time.Now(), 5*time.Minute, "hello")
|
||||
signer.sign()
|
||||
hash := signer.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "UNSIGNED-PAYLOAD", hash)
|
||||
}
|
||||
|
||||
func TestSignPrecomputedBodyChecksum(t *testing.T) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 0, "hello")
|
||||
signer.Request.Header.Set("X-Amz-Content-Sha256", "PRECOMPUTED")
|
||||
signer.sign()
|
||||
hash := signer.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "PRECOMPUTED", hash)
|
||||
}
|
||||
|
||||
func TestAnonymousCredentials(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: credentials.AnonymousCredentials})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
Sign(r)
|
||||
|
||||
urlQ := r.HTTPRequest.URL.Query()
|
||||
assert.Empty(t, urlQ.Get("X-Amz-Signature"))
|
||||
assert.Empty(t, urlQ.Get("X-Amz-Credential"))
|
||||
assert.Empty(t, urlQ.Get("X-Amz-SignedHeaders"))
|
||||
assert.Empty(t, urlQ.Get("X-Amz-Date"))
|
||||
|
||||
hQ := r.HTTPRequest.Header
|
||||
assert.Empty(t, hQ.Get("Authorization"))
|
||||
assert.Empty(t, hQ.Get("X-Amz-Date"))
|
||||
}
|
||||
|
||||
func TestIgnoreResignRequestWithValidCreds(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"),
|
||||
Region: aws.String("us-west-2"),
|
||||
})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
Sign(r)
|
||||
sig := r.HTTPRequest.Header.Get("Authorization")
|
||||
|
||||
Sign(r)
|
||||
assert.Equal(t, sig, r.HTTPRequest.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
func TestIgnorePreResignRequestWithValidCreds(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"),
|
||||
Region: aws.String("us-west-2"),
|
||||
})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
r.ExpireTime = time.Minute * 10
|
||||
|
||||
Sign(r)
|
||||
sig := r.HTTPRequest.Header.Get("X-Amz-Signature")
|
||||
|
||||
Sign(r)
|
||||
assert.Equal(t, sig, r.HTTPRequest.Header.Get("X-Amz-Signature"))
|
||||
}
|
||||
|
||||
func TestResignRequestExpiredCreds(t *testing.T) {
|
||||
creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: creds})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
Sign(r)
|
||||
querySig := r.HTTPRequest.Header.Get("Authorization")
|
||||
|
||||
creds.Expire()
|
||||
|
||||
Sign(r)
|
||||
assert.NotEqual(t, querySig, r.HTTPRequest.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
func TestPreResignRequestExpiredCreds(t *testing.T) {
|
||||
provider := &credentials.StaticProvider{credentials.Value{"AKID", "SECRET", "SESSION"}}
|
||||
creds := credentials.NewCredentials(provider)
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: creds})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
r.ExpireTime = time.Minute * 10
|
||||
|
||||
Sign(r)
|
||||
querySig := r.HTTPRequest.URL.Query().Get("X-Amz-Signature")
|
||||
|
||||
creds.Expire()
|
||||
r.Time = time.Now().Add(time.Hour * 48)
|
||||
|
||||
Sign(r)
|
||||
assert.NotEqual(t, querySig, r.HTTPRequest.URL.Query().Get("X-Amz-Signature"))
|
||||
}
|
||||
|
||||
func BenchmarkPresignRequest(b *testing.B) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 300*time.Second, "{}")
|
||||
for i := 0; i < b.N; i++ {
|
||||
signer.sign()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSignRequest(b *testing.B) {
|
||||
signer := buildSigner("dynamodb", "us-east-1", time.Now(), 0, "{}")
|
||||
for i := 0; i < b.N; i++ {
|
||||
signer.sign()
|
||||
}
|
||||
}
|
|
@ -3,8 +3,10 @@ package ec2
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -20,38 +22,34 @@ func fillPresignedURL(r *request.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
params := r.Params.(*CopySnapshotInput)
|
||||
origParams := r.Params.(*CopySnapshotInput)
|
||||
|
||||
// Stop if PresignedURL/DestinationRegion is set
|
||||
if params.PresignedUrl != nil || params.DestinationRegion != nil {
|
||||
if origParams.PresignedUrl != nil || origParams.DestinationRegion != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// First generate a copy of parameters
|
||||
r.Params = awsutil.CopyOf(r.Params)
|
||||
params = r.Params.(*CopySnapshotInput)
|
||||
origParams.DestinationRegion = r.Config.Region
|
||||
newParams := awsutil.CopyOf(r.Params).(*CopySnapshotInput)
|
||||
|
||||
// Set destination region. Avoids infinite handler loop.
|
||||
// Also needed to sign sub-request.
|
||||
params.DestinationRegion = r.Service.Config.Region
|
||||
|
||||
// Create a new client pointing at source region.
|
||||
// We will use this to presign the CopySnapshot request against
|
||||
// the source region
|
||||
config := r.Service.Config.Copy().
|
||||
// Create a new request based on the existing request. We will use this to
|
||||
// presign the CopySnapshot request against the source region.
|
||||
cfg := r.Config.Copy(aws.NewConfig().
|
||||
WithEndpoint("").
|
||||
WithRegion(*params.SourceRegion)
|
||||
WithRegion(aws.StringValue(origParams.SourceRegion)))
|
||||
|
||||
client := New(config)
|
||||
clientInfo := r.ClientInfo
|
||||
clientInfo.Endpoint, clientInfo.SigningRegion = endpoints.EndpointForRegion(
|
||||
clientInfo.ServiceName, aws.StringValue(cfg.Region), aws.BoolValue(cfg.DisableSSL))
|
||||
|
||||
// Presign a CopySnapshot request with modified params
|
||||
req, _ := client.CopySnapshotRequest(params)
|
||||
url, err := req.Presign(300 * time.Second) // 5 minutes should be enough.
|
||||
|
||||
if err != nil { // bubble error back up to original request
|
||||
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)
|
||||
url, err := req.Presign(5 * time.Minute) // 5 minutes should be enough.
|
||||
if err != nil { // bubble error back up to original request
|
||||
r.Error = err
|
||||
return
|
||||
}
|
||||
|
||||
// We have our URL, set it on params
|
||||
params.PresignedUrl = &url
|
||||
origParams.PresignedUrl = &url
|
||||
}
|
||||
|
|
35
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package ec2_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCopySnapshotPresignedURL(t *testing.T) {
|
||||
svc := ec2.New(unit.Session, &aws.Config{Region: aws.String("us-west-2")})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
// Doesn't panic on nil input
|
||||
req, _ := svc.CopySnapshotRequest(nil)
|
||||
req.Sign()
|
||||
})
|
||||
|
||||
req, _ := svc.CopySnapshotRequest(&ec2.CopySnapshotInput{
|
||||
SourceRegion: aws.String("us-west-1"),
|
||||
SourceSnapshotId: aws.String("snap-id"),
|
||||
})
|
||||
req.Sign()
|
||||
|
||||
b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
|
||||
q, _ := url.ParseQuery(string(b))
|
||||
url, _ := url.QueryUnescape(q.Get("PresignedUrl"))
|
||||
assert.Equal(t, "us-west-2", q.Get("DestinationRegion"))
|
||||
assert.Equal(t, "us-west-1", q.Get("SourceRegion"))
|
||||
assert.Regexp(t, `^https://ec2\.us-west-1\.amazonaws\.com/.+&DestinationRegion=us-west-2`, url)
|
||||
}
|
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go
generated
vendored
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go
generated
vendored
|
@ -758,3 +758,5 @@ type EC2API interface {
|
|||
|
||||
UnmonitorInstances(*ec2.UnmonitorInstancesInput) (*ec2.UnmonitorInstancesOutput, error)
|
||||
}
|
||||
|
||||
var _ EC2API = (*ec2.EC2)(nil)
|
||||
|
|
5188
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/examples_test.go
generated
vendored
Normal file
5188
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ec2/examples_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -4,52 +4,75 @@ package ec2
|
|||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/internal/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
|
||||
// Amazon Elastic Compute Cloud (Amazon EC2) provides resizable computing capacity
|
||||
// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your
|
||||
// need to invest in hardware up front, so you can develop and deploy applications
|
||||
// faster.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type EC2 struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom service initialization logic
|
||||
var initService func(*service.Service)
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// New returns a new EC2 client.
|
||||
func New(config *aws.Config) *EC2 {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "ec2",
|
||||
APIVersion: "2015-10-01",
|
||||
},
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "ec2"
|
||||
|
||||
// New creates a new instance of the EC2 client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a EC2 client from just a session.
|
||||
// svc := ec2.New(mySession)
|
||||
//
|
||||
// // Create a EC2 client with additional configuration
|
||||
// svc := ec2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2 {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *EC2 {
|
||||
svc := &EC2{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2015-10-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
// Run custom service initialization if present
|
||||
if initService != nil {
|
||||
initService(service)
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return &EC2{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a EC2 operation and runs any
|
||||
|
|
2364
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/iam/examples_test.go
generated
vendored
Normal file
2364
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/iam/examples_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go
generated
vendored
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go
generated
vendored
|
@ -506,3 +506,5 @@ type IAMAPI interface {
|
|||
|
||||
UploadSigningCertificate(*iam.UploadSigningCertificateInput) (*iam.UploadSigningCertificateOutput, error)
|
||||
}
|
||||
|
||||
var _ IAMAPI = (*iam.IAM)(nil)
|
||||
|
|
|
@ -4,12 +4,11 @@ package iam
|
|||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/internal/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/internal/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
|
||||
// AWS Identity and Access Management (IAM) is a web service that you can use
|
||||
|
@ -60,40 +59,64 @@ import (
|
|||
// secure your AWS resources. Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html).
|
||||
// This set of topics walk you through the process of signing a request using
|
||||
// an access key ID and secret access key.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type IAM struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom service initialization logic
|
||||
var initService func(*service.Service)
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// New returns a new IAM client.
|
||||
func New(config *aws.Config) *IAM {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "iam",
|
||||
APIVersion: "2010-05-08",
|
||||
},
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "iam"
|
||||
|
||||
// New creates a new instance of the IAM client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a IAM client from just a session.
|
||||
// svc := iam.New(mySession)
|
||||
//
|
||||
// // Create a IAM client with additional configuration
|
||||
// svc := iam.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *IAM {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *IAM {
|
||||
svc := &IAM{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2010-05-08",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
|
||||
|
||||
// Run custom service initialization if present
|
||||
if initService != nil {
|
||||
initService(service)
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return &IAM{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a IAM operation and runs any
|
||||
|
|
|
@ -30,13 +30,13 @@ func buildGetBucketLocation(r *request.Request) {
|
|||
}
|
||||
|
||||
func populateLocationConstraint(r *request.Request) {
|
||||
if r.ParamsFilled() && aws.StringValue(r.Service.Config.Region) != "us-east-1" {
|
||||
if r.ParamsFilled() && aws.StringValue(r.Config.Region) != "us-east-1" {
|
||||
in := r.Params.(*CreateBucketInput)
|
||||
if in.CreateBucketConfiguration == nil {
|
||||
r.Params = awsutil.CopyOf(r.Params)
|
||||
in = r.Params.(*CreateBucketInput)
|
||||
in.CreateBucketConfiguration = &CreateBucketConfiguration{
|
||||
LocationConstraint: r.Service.Config.Region,
|
||||
LocationConstraint: r.Config.Region,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
75
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/bucket_location_test.go
generated
vendored
Normal file
75
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/bucket_location_test.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package s3_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var s3LocationTests = []struct {
|
||||
body string
|
||||
loc string
|
||||
}{
|
||||
{`<?xml version="1.0" encoding="UTF-8"?><LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/"/>`, ``},
|
||||
{`<?xml version="1.0" encoding="UTF-8"?><LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">EU</LocationConstraint>`, `EU`},
|
||||
}
|
||||
|
||||
func TestGetBucketLocation(t *testing.T) {
|
||||
for _, test := range s3LocationTests {
|
||||
s := s3.New(unit.Session)
|
||||
s.Handlers.Send.Clear()
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
reader := ioutil.NopCloser(bytes.NewReader([]byte(test.body)))
|
||||
r.HTTPResponse = &http.Response{StatusCode: 200, Body: reader}
|
||||
})
|
||||
|
||||
resp, err := s.GetBucketLocation(&s3.GetBucketLocationInput{Bucket: aws.String("bucket")})
|
||||
assert.NoError(t, err)
|
||||
if test.loc == "" {
|
||||
assert.Nil(t, resp.LocationConstraint)
|
||||
} else {
|
||||
assert.Equal(t, test.loc, *resp.LocationConstraint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPopulateLocationConstraint(t *testing.T) {
|
||||
s := s3.New(unit.Session)
|
||||
in := &s3.CreateBucketInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
}
|
||||
req, _ := s.CreateBucketRequest(in)
|
||||
err := req.Build()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "mock-region", awsutil.ValuesAtPath(req.Params, "CreateBucketConfiguration.LocationConstraint")[0])
|
||||
assert.Nil(t, in.CreateBucketConfiguration) // don't modify original params
|
||||
}
|
||||
|
||||
func TestNoPopulateLocationConstraintIfProvided(t *testing.T) {
|
||||
s := s3.New(unit.Session)
|
||||
req, _ := s.CreateBucketRequest(&s3.CreateBucketInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
CreateBucketConfiguration: &s3.CreateBucketConfiguration{},
|
||||
})
|
||||
err := req.Build()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(awsutil.ValuesAtPath(req.Params, "CreateBucketConfiguration.LocationConstraint")))
|
||||
}
|
||||
|
||||
func TestNoPopulateLocationConstraintIfClassic(t *testing.T) {
|
||||
s := s3.New(unit.Session, &aws.Config{Region: aws.String("us-east-1")})
|
||||
req, _ := s.CreateBucketRequest(&s3.CreateBucketInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
})
|
||||
err := req.Build()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(awsutil.ValuesAtPath(req.Params, "CreateBucketConfiguration.LocationConstraint")))
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
package s3
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initService = func(s *service.Service) {
|
||||
initClient = func(c *client.Client) {
|
||||
// Support building custom host-style bucket endpoints
|
||||
s.Handlers.Build.PushFront(updateHostWithBucket)
|
||||
c.Handlers.Build.PushFront(updateHostWithBucket)
|
||||
|
||||
// Require SSL when using SSE keys
|
||||
s.Handlers.Validate.PushBack(validateSSERequiresSSL)
|
||||
s.Handlers.Build.PushBack(computeSSEKeys)
|
||||
c.Handlers.Validate.PushBack(validateSSERequiresSSL)
|
||||
c.Handlers.Build.PushBack(computeSSEKeys)
|
||||
|
||||
// S3 uses custom error unmarshaling logic
|
||||
s.Handlers.UnmarshalError.Clear()
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
c.Handlers.UnmarshalError.Clear()
|
||||
c.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
}
|
||||
|
||||
initRequest = func(r *request.Request) {
|
||||
|
|
92
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/customizations_test.go
generated
vendored
Normal file
92
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/customizations_test.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
package s3_test
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func assertMD5(t *testing.T, req *request.Request) {
|
||||
err := req.Build()
|
||||
assert.NoError(t, err)
|
||||
|
||||
b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
|
||||
out := md5.Sum(b)
|
||||
assert.NotEmpty(t, b)
|
||||
assert.Equal(t, base64.StdEncoding.EncodeToString(out[:]), req.HTTPRequest.Header.Get("Content-MD5"))
|
||||
}
|
||||
|
||||
func TestMD5InPutBucketCors(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutBucketCorsRequest(&s3.PutBucketCorsInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
CORSConfiguration: &s3.CORSConfiguration{
|
||||
CORSRules: []*s3.CORSRule{
|
||||
{
|
||||
AllowedMethods: []*string{aws.String("GET")},
|
||||
AllowedOrigins: []*string{aws.String("*")},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assertMD5(t, req)
|
||||
}
|
||||
|
||||
func TestMD5InPutBucketLifecycle(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutBucketLifecycleRequest(&s3.PutBucketLifecycleInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
LifecycleConfiguration: &s3.LifecycleConfiguration{
|
||||
Rules: []*s3.Rule{
|
||||
{
|
||||
ID: aws.String("ID"),
|
||||
Prefix: aws.String("Prefix"),
|
||||
Status: aws.String("Enabled"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assertMD5(t, req)
|
||||
}
|
||||
|
||||
func TestMD5InPutBucketPolicy(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutBucketPolicyRequest(&s3.PutBucketPolicyInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Policy: aws.String("{}"),
|
||||
})
|
||||
assertMD5(t, req)
|
||||
}
|
||||
|
||||
func TestMD5InPutBucketTagging(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutBucketTaggingRequest(&s3.PutBucketTaggingInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Tagging: &s3.Tagging{
|
||||
TagSet: []*s3.Tag{
|
||||
{Key: aws.String("KEY"), Value: aws.String("VALUE")},
|
||||
},
|
||||
},
|
||||
})
|
||||
assertMD5(t, req)
|
||||
}
|
||||
|
||||
func TestMD5InDeleteObjects(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.DeleteObjectsRequest(&s3.DeleteObjectsInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Delete: &s3.Delete{
|
||||
Objects: []*s3.ObjectIdentifier{
|
||||
{Key: aws.String("key")},
|
||||
},
|
||||
},
|
||||
})
|
||||
assertMD5(t, req)
|
||||
}
|
1600
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/examples_test.go
generated
vendored
Normal file
1600
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/examples_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go
generated
vendored
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go
generated
vendored
|
@ -24,7 +24,7 @@ func dnsCompatibleBucketName(bucket string) bool {
|
|||
// the host. This is false if S3ForcePathStyle is explicitly set or if the
|
||||
// bucket is not DNS compatible.
|
||||
func hostStyleBucketName(r *request.Request, bucket string) bool {
|
||||
if aws.BoolValue(r.Service.Config.S3ForcePathStyle) {
|
||||
if aws.BoolValue(r.Config.S3ForcePathStyle) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
75
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/host_style_bucket_test.go
generated
vendored
Normal file
75
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/host_style_bucket_test.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package s3_test
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
type s3BucketTest struct {
|
||||
bucket string
|
||||
url string
|
||||
}
|
||||
|
||||
var (
|
||||
sslTests = []s3BucketTest{
|
||||
{"abc", "https://abc.s3.mock-region.amazonaws.com/"},
|
||||
{"a$b$c", "https://s3.mock-region.amazonaws.com/a%24b%24c"},
|
||||
{"a.b.c", "https://s3.mock-region.amazonaws.com/a.b.c"},
|
||||
{"a..bc", "https://s3.mock-region.amazonaws.com/a..bc"},
|
||||
}
|
||||
|
||||
nosslTests = []s3BucketTest{
|
||||
{"a.b.c", "http://a.b.c.s3.mock-region.amazonaws.com/"},
|
||||
{"a..bc", "http://s3.mock-region.amazonaws.com/a..bc"},
|
||||
}
|
||||
|
||||
forcepathTests = []s3BucketTest{
|
||||
{"abc", "https://s3.mock-region.amazonaws.com/abc"},
|
||||
{"a$b$c", "https://s3.mock-region.amazonaws.com/a%24b%24c"},
|
||||
{"a.b.c", "https://s3.mock-region.amazonaws.com/a.b.c"},
|
||||
{"a..bc", "https://s3.mock-region.amazonaws.com/a..bc"},
|
||||
}
|
||||
)
|
||||
|
||||
func runTests(t *testing.T, svc *s3.S3, tests []s3BucketTest) {
|
||||
for _, test := range tests {
|
||||
req, _ := svc.ListObjectsRequest(&s3.ListObjectsInput{Bucket: &test.bucket})
|
||||
req.Build()
|
||||
assert.Equal(t, test.url, req.HTTPRequest.URL.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostStyleBucketBuild(t *testing.T) {
|
||||
s := s3.New(unit.Session)
|
||||
runTests(t, s, sslTests)
|
||||
}
|
||||
|
||||
func TestHostStyleBucketBuildNoSSL(t *testing.T) {
|
||||
s := s3.New(unit.Session, &aws.Config{DisableSSL: aws.Bool(true)})
|
||||
runTests(t, s, nosslTests)
|
||||
}
|
||||
|
||||
func TestPathStyleBucketBuild(t *testing.T) {
|
||||
s := s3.New(unit.Session, &aws.Config{S3ForcePathStyle: aws.Bool(true)})
|
||||
runTests(t, s, forcepathTests)
|
||||
}
|
||||
|
||||
func TestHostStyleBucketGetBucketLocation(t *testing.T) {
|
||||
s := s3.New(unit.Session)
|
||||
req, _ := s.GetBucketLocationRequest(&s3.GetBucketLocationInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
})
|
||||
|
||||
req.Build()
|
||||
require.NoError(t, req.Error)
|
||||
u, _ := url.Parse(req.HTTPRequest.URL.String())
|
||||
assert.NotContains(t, u.Host, "bucket")
|
||||
assert.Contains(t, u.Path, "bucket")
|
||||
}
|
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3iface/interface.go
generated
vendored
2
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3iface/interface.go
generated
vendored
|
@ -242,3 +242,5 @@ type S3API interface {
|
|||
|
||||
UploadPartCopy(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error)
|
||||
}
|
||||
|
||||
var _ S3API = (*s3.S3)(nil)
|
||||
|
|
3
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/doc.go
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
// Package s3manager provides utilities to upload and download objects from
|
||||
// S3 concurrently. Helpful for when working with large objects.
|
||||
package s3manager
|
131
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/download.go
generated
vendored
131
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/download.go
generated
vendored
|
@ -9,27 +9,23 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3iface"
|
||||
)
|
||||
|
||||
// DefaultDownloadPartSize is the default range of bytes to get at a time when
|
||||
// using Download().
|
||||
var DefaultDownloadPartSize int64 = 1024 * 1024 * 5
|
||||
const DefaultDownloadPartSize = 1024 * 1024 * 5
|
||||
|
||||
// DefaultDownloadConcurrency is the default number of goroutines to spin up
|
||||
// when using Download().
|
||||
var DefaultDownloadConcurrency = 5
|
||||
const DefaultDownloadConcurrency = 5
|
||||
|
||||
// DefaultDownloadOptions is the default set of options used when opts is nil
|
||||
// in Download().
|
||||
var DefaultDownloadOptions = &DownloadOptions{
|
||||
PartSize: DefaultDownloadPartSize,
|
||||
Concurrency: DefaultDownloadConcurrency,
|
||||
}
|
||||
|
||||
// DownloadOptions keeps tracks of extra options to pass to an Download() call.
|
||||
type DownloadOptions struct {
|
||||
// The Downloader structure that calls Download(). It is safe to call Download()
|
||||
// on this structure for multiple objects and across concurrent goroutines.
|
||||
// Mutating the Downloader's properties is not safe to be done concurrently.
|
||||
type Downloader struct {
|
||||
// The buffer size (in bytes) to use when buffering data into chunks and
|
||||
// sending them as parts to S3. The minimum allowed part size is 5MB, and
|
||||
// if this value is set to zero, the DefaultPartSize value will be used.
|
||||
|
@ -39,45 +35,96 @@ type DownloadOptions struct {
|
|||
// If this is set to zero, the DefaultConcurrency value will be used.
|
||||
Concurrency int
|
||||
|
||||
// An S3 client to use when performing downloads. Leave this as nil to use
|
||||
// a default client.
|
||||
// An S3 client to use when performing downloads.
|
||||
S3 s3iface.S3API
|
||||
}
|
||||
|
||||
// NewDownloader creates a new Downloader structure that downloads an object
|
||||
// from S3 in concurrent chunks. Pass in an optional DownloadOptions struct
|
||||
// to customize the downloader behavior.
|
||||
func NewDownloader(opts *DownloadOptions) *Downloader {
|
||||
if opts == nil {
|
||||
opts = DefaultDownloadOptions
|
||||
// NewDownloader creates a new Downloader instance to downloads objects from
|
||||
// S3 in concurrent chunks. Pass in additional functional options to customize
|
||||
// the downloader behavior. Requires a client.ConfigProvider in order to create
|
||||
// a S3 service client. The session.Session satisfies the client.ConfigProvider
|
||||
// interface.
|
||||
//
|
||||
// Example:
|
||||
// // The session the S3 Downloader will use
|
||||
// sess := session.New()
|
||||
//
|
||||
// // Create a downloader with the session and default options
|
||||
// downloader := s3manager.NewDownloader(sess)
|
||||
//
|
||||
// // Create a downloader with the session and custom options
|
||||
// downloader := s3manager.NewDownloader(sess, func(d *s3manager.Uploader) {
|
||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewDownloader(c client.ConfigProvider, options ...func(*Downloader)) *Downloader {
|
||||
d := &Downloader{
|
||||
S3: s3.New(c),
|
||||
PartSize: DefaultDownloadPartSize,
|
||||
Concurrency: DefaultDownloadConcurrency,
|
||||
}
|
||||
return &Downloader{opts: opts}
|
||||
for _, option := range options {
|
||||
option(d)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// The Downloader structure that calls Download(). It is safe to call Download()
|
||||
// on this structure for multiple objects and across concurrent goroutines.
|
||||
type Downloader struct {
|
||||
opts *DownloadOptions
|
||||
// NewDownloaderWithClient creates a new Downloader instance to downloads
|
||||
// objects from S3 in concurrent chunks. Pass in additional functional
|
||||
// options to customize the downloader behavior. Requires a S3 service client
|
||||
// to make S3 API calls.
|
||||
//
|
||||
// Example:
|
||||
// // The S3 client the S3 Downloader will use
|
||||
// s3Svc := s3.new(session.New())
|
||||
//
|
||||
// // Create a downloader with the s3 client and default options
|
||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc)
|
||||
//
|
||||
// // Create a downloader with the s3 client and custom options
|
||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc, func(d *s3manager.Uploader) {
|
||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewDownloaderWithClient(svc s3iface.S3API, options ...func(*Downloader)) *Downloader {
|
||||
d := &Downloader{
|
||||
S3: svc,
|
||||
PartSize: DefaultDownloadPartSize,
|
||||
Concurrency: DefaultDownloadConcurrency,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(d)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Download downloads an object in S3 and writes the payload into w using
|
||||
// concurrent GET requests.
|
||||
//
|
||||
// It is safe to call this method for multiple objects and across concurrent
|
||||
// goroutines.
|
||||
// Additional functional options can be provided to configure the individual
|
||||
// upload. These options are copies of the Uploader instance Upload is called from.
|
||||
// Modifying the options will not impact the original Uploader instance.
|
||||
//
|
||||
// It is safe to call this method concurrently across goroutines.
|
||||
//
|
||||
// The w io.WriterAt can be satisfied by an os.File to do multipart concurrent
|
||||
// downloads, or in memory []byte wrapper using aws.WriteAtBuffer.
|
||||
func (d *Downloader) Download(w io.WriterAt, input *s3.GetObjectInput) (n int64, err error) {
|
||||
impl := downloader{w: w, in: input, opts: *d.opts}
|
||||
func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error) {
|
||||
impl := downloader{w: w, in: input, ctx: d}
|
||||
|
||||
for _, option := range options {
|
||||
option(&impl.ctx)
|
||||
}
|
||||
|
||||
return impl.download()
|
||||
}
|
||||
|
||||
// downloader is the implementation structure used internally by Downloader.
|
||||
type downloader struct {
|
||||
opts DownloadOptions
|
||||
in *s3.GetObjectInput
|
||||
w io.WriterAt
|
||||
ctx Downloader
|
||||
|
||||
in *s3.GetObjectInput
|
||||
w io.WriterAt
|
||||
|
||||
wg sync.WaitGroup
|
||||
m sync.Mutex
|
||||
|
@ -92,16 +139,12 @@ type downloader struct {
|
|||
func (d *downloader) init() {
|
||||
d.totalBytes = -1
|
||||
|
||||
if d.opts.Concurrency == 0 {
|
||||
d.opts.Concurrency = DefaultDownloadConcurrency
|
||||
if d.ctx.Concurrency == 0 {
|
||||
d.ctx.Concurrency = DefaultDownloadConcurrency
|
||||
}
|
||||
|
||||
if d.opts.PartSize == 0 {
|
||||
d.opts.PartSize = DefaultDownloadPartSize
|
||||
}
|
||||
|
||||
if d.opts.S3 == nil {
|
||||
d.opts.S3 = s3.New(nil)
|
||||
if d.ctx.PartSize == 0 {
|
||||
d.ctx.PartSize = DefaultDownloadPartSize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,8 +154,8 @@ func (d *downloader) download() (n int64, err error) {
|
|||
d.init()
|
||||
|
||||
// Spin up workers
|
||||
ch := make(chan dlchunk, d.opts.Concurrency)
|
||||
for i := 0; i < d.opts.Concurrency; i++ {
|
||||
ch := make(chan dlchunk, d.ctx.Concurrency)
|
||||
for i := 0; i < d.ctx.Concurrency; i++ {
|
||||
d.wg.Add(1)
|
||||
go d.downloadPart(ch)
|
||||
}
|
||||
|
@ -136,8 +179,8 @@ func (d *downloader) download() (n int64, err error) {
|
|||
}
|
||||
|
||||
// Queue the next range of bytes to read.
|
||||
ch <- dlchunk{w: d.w, start: d.pos, size: d.opts.PartSize}
|
||||
d.pos += d.opts.PartSize
|
||||
ch <- dlchunk{w: d.w, start: d.pos, size: d.ctx.PartSize}
|
||||
d.pos += d.ctx.PartSize
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
|
@ -171,7 +214,7 @@ func (d *downloader) downloadPart(ch chan dlchunk) {
|
|||
chunk.start, chunk.start+chunk.size-1)
|
||||
in.Range = &rng
|
||||
|
||||
resp, err := d.opts.S3.GetObject(in)
|
||||
resp, err := d.ctx.S3.GetObject(in)
|
||||
if err != nil {
|
||||
d.seterr(err)
|
||||
} else {
|
||||
|
|
144
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/download_test.go
generated
vendored
Normal file
144
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/download_test.go
generated
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
package s3manager_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
)
|
||||
|
||||
func dlLoggingSvc(data []byte) (*s3.S3, *[]string, *[]string) {
|
||||
var m sync.Mutex
|
||||
names := []string{}
|
||||
ranges := []string{}
|
||||
|
||||
svc := s3.New(unit.Session)
|
||||
svc.Handlers.Send.Clear()
|
||||
svc.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
names = append(names, r.Operation.Name)
|
||||
ranges = append(ranges, *r.Params.(*s3.GetObjectInput).Range)
|
||||
|
||||
rerng := regexp.MustCompile(`bytes=(\d+)-(\d+)`)
|
||||
rng := rerng.FindStringSubmatch(r.HTTPRequest.Header.Get("Range"))
|
||||
start, _ := strconv.ParseInt(rng[1], 10, 64)
|
||||
fin, _ := strconv.ParseInt(rng[2], 10, 64)
|
||||
fin++
|
||||
|
||||
if fin > int64(len(data)) {
|
||||
fin = int64(len(data))
|
||||
}
|
||||
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(data[start:fin])),
|
||||
Header: http.Header{},
|
||||
}
|
||||
r.HTTPResponse.Header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d",
|
||||
start, fin, len(data)))
|
||||
})
|
||||
|
||||
return svc, &names, &ranges
|
||||
}
|
||||
|
||||
func TestDownloadOrder(t *testing.T) {
|
||||
s, names, ranges := dlLoggingSvc(buf12MB)
|
||||
|
||||
d := s3manager.NewDownloaderWithClient(s, func(d *s3manager.Downloader) {
|
||||
d.Concurrency = 1
|
||||
})
|
||||
w := &aws.WriteAtBuffer{}
|
||||
n, err := d.Download(w, &s3.GetObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(len(buf12MB)), n)
|
||||
assert.Equal(t, []string{"GetObject", "GetObject", "GetObject"}, *names)
|
||||
assert.Equal(t, []string{"bytes=0-5242879", "bytes=5242880-10485759", "bytes=10485760-15728639"}, *ranges)
|
||||
|
||||
count := 0
|
||||
for _, b := range w.Bytes() {
|
||||
count += int(b)
|
||||
}
|
||||
assert.Equal(t, 0, count)
|
||||
}
|
||||
|
||||
func TestDownloadZero(t *testing.T) {
|
||||
s, names, ranges := dlLoggingSvc([]byte{})
|
||||
|
||||
d := s3manager.NewDownloaderWithClient(s)
|
||||
w := &aws.WriteAtBuffer{}
|
||||
n, err := d.Download(w, &s3.GetObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(0), n)
|
||||
assert.Equal(t, []string{"GetObject"}, *names)
|
||||
assert.Equal(t, []string{"bytes=0-5242879"}, *ranges)
|
||||
}
|
||||
|
||||
func TestDownloadSetPartSize(t *testing.T) {
|
||||
s, names, ranges := dlLoggingSvc([]byte{1, 2, 3})
|
||||
|
||||
d := s3manager.NewDownloaderWithClient(s, func(d *s3manager.Downloader) {
|
||||
d.Concurrency = 1
|
||||
d.PartSize = 1
|
||||
})
|
||||
w := &aws.WriteAtBuffer{}
|
||||
n, err := d.Download(w, &s3.GetObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(3), n)
|
||||
assert.Equal(t, []string{"GetObject", "GetObject", "GetObject"}, *names)
|
||||
assert.Equal(t, []string{"bytes=0-0", "bytes=1-1", "bytes=2-2"}, *ranges)
|
||||
assert.Equal(t, []byte{1, 2, 3}, w.Bytes())
|
||||
}
|
||||
|
||||
func TestDownloadError(t *testing.T) {
|
||||
s, names, _ := dlLoggingSvc([]byte{1, 2, 3})
|
||||
|
||||
num := 0
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
num++
|
||||
if num > 1 {
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
|
||||
}
|
||||
})
|
||||
|
||||
d := s3manager.NewDownloaderWithClient(s, func(d *s3manager.Downloader) {
|
||||
d.Concurrency = 1
|
||||
d.PartSize = 1
|
||||
})
|
||||
w := &aws.WriteAtBuffer{}
|
||||
n, err := d.Download(w, &s3.GetObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
})
|
||||
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, int64(1), n)
|
||||
assert.Equal(t, []string{"GetObject", "GetObject"}, *names)
|
||||
assert.Equal(t, []byte{1}, w.Bytes())
|
||||
}
|
4
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/shared_test.go
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/shared_test.go
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
package s3manager_test
|
||||
|
||||
var buf12MB = make([]byte, 1024*1024*12)
|
||||
var buf2MB = make([]byte, 1024*1024*2)
|
199
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/upload.go
generated
vendored
199
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/upload.go
generated
vendored
|
@ -10,34 +10,26 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3iface"
|
||||
)
|
||||
|
||||
// MaxUploadParts is the maximum allowed number of parts in a multi-part upload
|
||||
// on Amazon S3.
|
||||
var MaxUploadParts = 10000
|
||||
const MaxUploadParts = 10000
|
||||
|
||||
// MinUploadPartSize is the minimum allowed part size when uploading a part to
|
||||
// Amazon S3.
|
||||
var MinUploadPartSize int64 = 1024 * 1024 * 5
|
||||
const MinUploadPartSize int64 = 1024 * 1024 * 5
|
||||
|
||||
// DefaultUploadPartSize is the default part size to buffer chunks of a
|
||||
// payload into.
|
||||
var DefaultUploadPartSize = MinUploadPartSize
|
||||
const DefaultUploadPartSize = MinUploadPartSize
|
||||
|
||||
// DefaultUploadConcurrency is the default number of goroutines to spin up when
|
||||
// using Upload().
|
||||
var DefaultUploadConcurrency = 5
|
||||
|
||||
// DefaultUploadOptions is the default set of options used when opts is nil in
|
||||
// Upload().
|
||||
var DefaultUploadOptions = &UploadOptions{
|
||||
PartSize: DefaultUploadPartSize,
|
||||
Concurrency: DefaultUploadConcurrency,
|
||||
LeavePartsOnError: false,
|
||||
S3: nil,
|
||||
}
|
||||
const DefaultUploadConcurrency = 5
|
||||
|
||||
// A MultiUploadFailure wraps a failed S3 multipart upload. An error returned
|
||||
// will satisfy this interface when a multi part upload failed to upload all
|
||||
|
@ -205,8 +197,10 @@ type UploadOutput struct {
|
|||
UploadID string
|
||||
}
|
||||
|
||||
// UploadOptions keeps tracks of extra options to pass to an Upload() call.
|
||||
type UploadOptions struct {
|
||||
// The Uploader structure that calls Upload(). It is safe to call Upload()
|
||||
// on this structure for multiple objects and across concurrent goroutines.
|
||||
// Mutating the Uploader's properties is not safe to be done concurrently.
|
||||
type Uploader struct {
|
||||
// The buffer size (in bytes) to use when buffering data into chunks and
|
||||
// sending them as parts to S3. The minimum allowed part size is 5MB, and
|
||||
// if this value is set to zero, the DefaultPartSize value will be used.
|
||||
|
@ -224,43 +218,121 @@ type UploadOptions struct {
|
|||
// space usage on S3 and will add additional costs if not cleaned up.
|
||||
LeavePartsOnError bool
|
||||
|
||||
// The client to use when uploading to S3. Leave this as nil to use the
|
||||
// default S3 client.
|
||||
// MaxUploadParts is the max number of parts which will be uploaded to S3.
|
||||
// Will be used to calculate the partsize of the object to be uploaded.
|
||||
// E.g: 5GB file, with MaxUploadParts set to 100, will upload the file
|
||||
// as 100, 50MB parts.
|
||||
// With a limited of s3.MaxUploadParts (10,000 parts).
|
||||
MaxUploadParts int
|
||||
|
||||
// The client to use when uploading to S3.
|
||||
S3 s3iface.S3API
|
||||
}
|
||||
|
||||
// NewUploader creates a new Uploader object to upload data to S3. Pass in
|
||||
// an optional opts structure to customize the uploader behavior.
|
||||
func NewUploader(opts *UploadOptions) *Uploader {
|
||||
if opts == nil {
|
||||
opts = DefaultUploadOptions
|
||||
// NewUploader creates a new Uploader instance to upload objects to S3. Pass In
|
||||
// additional functional options to customize the uploader's behavior. Requires a
|
||||
// client.ConfigProvider in order to create a S3 service client. The session.Session
|
||||
// satisfies the client.ConfigProvider interface.
|
||||
//
|
||||
// Example:
|
||||
// // The session the S3 Uploader will use
|
||||
// sess := session.New()
|
||||
//
|
||||
// // Create an uploader with the session and default options
|
||||
// uploader := s3manager.NewUploader(sess)
|
||||
//
|
||||
// // Create an uploader with the session and custom options
|
||||
// uploader := s3manager.NewUploader(session, func(u *s3manager.Uploader) {
|
||||
// u.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewUploader(c client.ConfigProvider, options ...func(*Uploader)) *Uploader {
|
||||
u := &Uploader{
|
||||
S3: s3.New(c),
|
||||
PartSize: DefaultUploadPartSize,
|
||||
Concurrency: DefaultUploadConcurrency,
|
||||
LeavePartsOnError: false,
|
||||
MaxUploadParts: MaxUploadParts,
|
||||
}
|
||||
return &Uploader{opts: opts}
|
||||
|
||||
for _, option := range options {
|
||||
option(u)
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// The Uploader structure that calls Upload(). It is safe to call Upload()
|
||||
// on this structure for multiple objects and across concurrent goroutines.
|
||||
type Uploader struct {
|
||||
opts *UploadOptions
|
||||
// NewUploaderWithClient creates a new Uploader instance to upload objects to S3. Pass in
|
||||
// additional functional options to customize the uploader's behavior. Requires
|
||||
// a S3 service client to make S3 API calls.
|
||||
//
|
||||
// Example:
|
||||
// // S3 service client the Upload manager will use.
|
||||
// s3Svc := s3.New(session.New())
|
||||
//
|
||||
// // Create an uploader with S3 client and default options
|
||||
// uploader := s3manager.NewUploaderWithClient(s3Svc)
|
||||
//
|
||||
// // Create an uploader with S3 client and custom options
|
||||
// uploader := s3manager.NewUploaderWithClient(s3Svc, func(u *s3manager.Uploader) {
|
||||
// u.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewUploaderWithClient(svc s3iface.S3API, options ...func(*Uploader)) *Uploader {
|
||||
u := &Uploader{
|
||||
S3: svc,
|
||||
PartSize: DefaultUploadPartSize,
|
||||
Concurrency: DefaultUploadConcurrency,
|
||||
LeavePartsOnError: false,
|
||||
MaxUploadParts: MaxUploadParts,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(u)
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// Upload uploads an object to S3, intelligently buffering large files into
|
||||
// smaller chunks and sending them in parallel across multiple goroutines. You
|
||||
// can configure the buffer size and concurrency through the opts parameter.
|
||||
// can configure the buffer size and concurrency through the Uploader's parameters.
|
||||
//
|
||||
// If opts is set to nil, DefaultUploadOptions will be used.
|
||||
// Additional functional options can be provided to configure the individual
|
||||
// upload. These options are copies of the Uploader instance Upload is called from.
|
||||
// Modifying the options will not impact the original Uploader instance.
|
||||
//
|
||||
// It is safe to call this method for multiple objects and across concurrent
|
||||
// goroutines.
|
||||
func (u *Uploader) Upload(input *UploadInput) (*UploadOutput, error) {
|
||||
i := uploader{in: input, opts: *u.opts}
|
||||
// It is safe to call this method concurrently across goroutines.
|
||||
//
|
||||
// Example:
|
||||
// // Upload input parameters
|
||||
// upParams := &s3manager.UploadInput{
|
||||
// Bucket: &bucketName,
|
||||
// Key: &keyName,
|
||||
// Body: file,
|
||||
// }
|
||||
//
|
||||
// // Perform an upload.
|
||||
// result, err := uploader.Upload(upParams)
|
||||
//
|
||||
// // Perform upload with options different than the those in the Uploader.
|
||||
// result, err := uploader.Upload(upParams, func(u *s3manager.Uploader) {
|
||||
// u.PartSize = 10 * 1024 * 1024 // 10MB part size
|
||||
// u.LeavePartsOnError = true // Dont delete the parts if the upload fails.
|
||||
// })
|
||||
func (u Uploader) Upload(input *UploadInput, options ...func(*Uploader)) (*UploadOutput, error) {
|
||||
i := uploader{in: input, ctx: u}
|
||||
|
||||
for _, option := range options {
|
||||
option(&i.ctx)
|
||||
}
|
||||
|
||||
return i.upload()
|
||||
}
|
||||
|
||||
// internal structure to manage an upload to S3.
|
||||
type uploader struct {
|
||||
in *UploadInput
|
||||
opts UploadOptions
|
||||
ctx Uploader
|
||||
|
||||
in *UploadInput
|
||||
|
||||
readerPos int64 // current reader position
|
||||
totalSize int64 // set to -1 if the size is not known
|
||||
|
@ -271,7 +343,7 @@ type uploader struct {
|
|||
func (u *uploader) upload() (*UploadOutput, error) {
|
||||
u.init()
|
||||
|
||||
if u.opts.PartSize < MinUploadPartSize {
|
||||
if u.ctx.PartSize < MinUploadPartSize {
|
||||
msg := fmt.Sprintf("part size must be at least %d bytes", MinUploadPartSize)
|
||||
return nil, awserr.New("ConfigError", msg, nil)
|
||||
}
|
||||
|
@ -290,14 +362,11 @@ func (u *uploader) upload() (*UploadOutput, error) {
|
|||
|
||||
// init will initialize all default options.
|
||||
func (u *uploader) init() {
|
||||
if u.opts.S3 == nil {
|
||||
u.opts.S3 = s3.New(nil)
|
||||
if u.ctx.Concurrency == 0 {
|
||||
u.ctx.Concurrency = DefaultUploadConcurrency
|
||||
}
|
||||
if u.opts.Concurrency == 0 {
|
||||
u.opts.Concurrency = DefaultUploadConcurrency
|
||||
}
|
||||
if u.opts.PartSize == 0 {
|
||||
u.opts.PartSize = DefaultUploadPartSize
|
||||
if u.ctx.PartSize == 0 {
|
||||
u.ctx.PartSize = DefaultUploadPartSize
|
||||
}
|
||||
|
||||
// Try to get the total size for some optimizations
|
||||
|
@ -320,9 +389,12 @@ func (u *uploader) initSize() {
|
|||
}
|
||||
u.totalSize = n
|
||||
|
||||
// try to adjust partSize if it is too small
|
||||
if u.totalSize/u.opts.PartSize >= int64(MaxUploadParts) {
|
||||
u.opts.PartSize = u.totalSize / int64(MaxUploadParts)
|
||||
// Try to adjust partSize if it is too small and account for
|
||||
// integer division truncation.
|
||||
if u.totalSize/u.ctx.PartSize >= int64(u.ctx.MaxUploadParts) {
|
||||
// Add one to the part size to account for remainders
|
||||
// during the size calculation. e.g odd number of bytes.
|
||||
u.ctx.PartSize = (u.totalSize / int64(u.ctx.MaxUploadParts)) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,14 +408,14 @@ func (u *uploader) nextReader() (io.ReadSeeker, error) {
|
|||
case io.ReaderAt:
|
||||
var err error
|
||||
|
||||
n := u.opts.PartSize
|
||||
n := u.ctx.PartSize
|
||||
if u.totalSize >= 0 {
|
||||
bytesLeft := u.totalSize - u.readerPos
|
||||
|
||||
if bytesLeft == 0 {
|
||||
err = io.EOF
|
||||
n = bytesLeft
|
||||
} else if bytesLeft <= u.opts.PartSize {
|
||||
} else if bytesLeft <= u.ctx.PartSize {
|
||||
err = io.ErrUnexpectedEOF
|
||||
n = bytesLeft
|
||||
}
|
||||
|
@ -355,7 +427,7 @@ func (u *uploader) nextReader() (io.ReadSeeker, error) {
|
|||
return buf, err
|
||||
|
||||
default:
|
||||
packet := make([]byte, u.opts.PartSize)
|
||||
packet := make([]byte, u.ctx.PartSize)
|
||||
n, err := io.ReadFull(u.in.Body, packet)
|
||||
u.readerPos += int64(n)
|
||||
|
||||
|
@ -371,7 +443,7 @@ func (u *uploader) singlePart(buf io.ReadSeeker) (*UploadOutput, error) {
|
|||
awsutil.Copy(params, u.in)
|
||||
params.Body = buf
|
||||
|
||||
req, out := u.opts.S3.PutObjectRequest(params)
|
||||
req, out := u.ctx.S3.PutObjectRequest(params)
|
||||
if err := req.Send(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -414,15 +486,15 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker) (*UploadOutput, error) {
|
|||
awsutil.Copy(params, u.in)
|
||||
|
||||
// Create the multipart
|
||||
resp, err := u.opts.S3.CreateMultipartUpload(params)
|
||||
resp, err := u.ctx.S3.CreateMultipartUpload(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.uploadID = *resp.UploadId
|
||||
|
||||
// Create the workers
|
||||
ch := make(chan chunk, u.opts.Concurrency)
|
||||
for i := 0; i < u.opts.Concurrency; i++ {
|
||||
ch := make(chan chunk, u.ctx.Concurrency)
|
||||
for i := 0; i < u.ctx.Concurrency; i++ {
|
||||
u.wg.Add(1)
|
||||
go u.readChunk(ch)
|
||||
}
|
||||
|
@ -434,13 +506,18 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker) (*UploadOutput, error) {
|
|||
// Read and queue the rest of the parts
|
||||
for u.geterr() == nil {
|
||||
// This upload exceeded maximum number of supported parts, error now.
|
||||
if num > int64(MaxUploadParts) {
|
||||
msg := fmt.Sprintf("exceeded total allowed parts (%d). "+
|
||||
"Adjust PartSize to fit in this limit", MaxUploadParts)
|
||||
if num > int64(u.ctx.MaxUploadParts) || num > int64(MaxUploadParts) {
|
||||
var msg string
|
||||
if num > int64(u.ctx.MaxUploadParts) {
|
||||
msg = fmt.Sprintf("exceeded total allowed configured MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
||||
u.ctx.MaxUploadParts)
|
||||
} else {
|
||||
msg = fmt.Sprintf("exceeded total allowed S3 limit MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
||||
MaxUploadParts)
|
||||
}
|
||||
u.seterr(awserr.New("TotalPartsExceeded", msg, nil))
|
||||
break
|
||||
}
|
||||
|
||||
num++
|
||||
|
||||
buf, err := u.nextReader()
|
||||
|
@ -502,7 +579,7 @@ func (u *multiuploader) readChunk(ch chan chunk) {
|
|||
// send performs an UploadPart request and keeps track of the completed
|
||||
// part information.
|
||||
func (u *multiuploader) send(c chunk) error {
|
||||
resp, err := u.opts.S3.UploadPart(&s3.UploadPartInput{
|
||||
resp, err := u.ctx.S3.UploadPart(&s3.UploadPartInput{
|
||||
Bucket: u.in.Bucket,
|
||||
Key: u.in.Key,
|
||||
Body: c.buf,
|
||||
|
@ -542,11 +619,11 @@ func (u *multiuploader) seterr(e error) {
|
|||
|
||||
// fail will abort the multipart unless LeavePartsOnError is set to true.
|
||||
func (u *multiuploader) fail() {
|
||||
if u.opts.LeavePartsOnError {
|
||||
if u.ctx.LeavePartsOnError {
|
||||
return
|
||||
}
|
||||
|
||||
u.opts.S3.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
|
||||
u.ctx.S3.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
|
||||
Bucket: u.in.Bucket,
|
||||
Key: u.in.Key,
|
||||
UploadId: &u.uploadID,
|
||||
|
@ -563,7 +640,7 @@ func (u *multiuploader) complete() *s3.CompleteMultipartUploadOutput {
|
|||
// Parts must be sorted in PartNumber order.
|
||||
sort.Sort(u.parts)
|
||||
|
||||
resp, err := u.opts.S3.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
|
||||
resp, err := u.ctx.S3.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
|
||||
Bucket: u.in.Bucket,
|
||||
Key: u.in.Key,
|
||||
UploadId: &u.uploadID,
|
||||
|
|
469
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/upload_test.go
generated
vendored
Normal file
469
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager/upload_test.go
generated
vendored
Normal file
|
@ -0,0 +1,469 @@
|
|||
package s3manager_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var emptyList = []string{}
|
||||
|
||||
func val(i interface{}, s string) interface{} {
|
||||
return awsutil.ValuesAtPath(i, s)[0]
|
||||
}
|
||||
|
||||
func contains(src []string, s string) bool {
|
||||
for _, v := range src {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func loggingSvc(ignoreOps []string) (*s3.S3, *[]string, *[]interface{}) {
|
||||
var m sync.Mutex
|
||||
partNum := 0
|
||||
names := []string{}
|
||||
params := []interface{}{}
|
||||
svc := s3.New(unit.Session)
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.UnmarshalError.Clear()
|
||||
svc.Handlers.Send.Clear()
|
||||
svc.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if !contains(ignoreOps, r.Operation.Name) {
|
||||
names = append(names, r.Operation.Name)
|
||||
params = append(params, r.Params)
|
||||
}
|
||||
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
|
||||
switch data := r.Data.(type) {
|
||||
case *s3.CreateMultipartUploadOutput:
|
||||
data.UploadId = aws.String("UPLOAD-ID")
|
||||
case *s3.UploadPartOutput:
|
||||
partNum++
|
||||
data.ETag = aws.String(fmt.Sprintf("ETAG%d", partNum))
|
||||
case *s3.CompleteMultipartUploadOutput:
|
||||
data.Location = aws.String("https://location")
|
||||
data.VersionId = aws.String("VERSION-ID")
|
||||
case *s3.PutObjectOutput:
|
||||
data.VersionId = aws.String("VERSION-ID")
|
||||
}
|
||||
})
|
||||
|
||||
return svc, &names, ¶ms
|
||||
}
|
||||
|
||||
func buflen(i interface{}) int {
|
||||
r := i.(io.Reader)
|
||||
b, _ := ioutil.ReadAll(r)
|
||||
return len(b)
|
||||
}
|
||||
|
||||
func TestUploadOrderMulti(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
u := s3manager.NewUploaderWithClient(s)
|
||||
|
||||
resp, err := u.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
ServerSideEncryption: aws.String("AES256"),
|
||||
ContentType: aws.String("content/type"),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops)
|
||||
assert.Equal(t, "https://location", resp.Location)
|
||||
assert.Equal(t, "UPLOAD-ID", resp.UploadID)
|
||||
assert.Equal(t, aws.String("VERSION-ID"), resp.VersionID)
|
||||
|
||||
// Validate input values
|
||||
|
||||
// UploadPart
|
||||
assert.Equal(t, "UPLOAD-ID", val((*args)[1], "UploadId"))
|
||||
assert.Equal(t, "UPLOAD-ID", val((*args)[2], "UploadId"))
|
||||
assert.Equal(t, "UPLOAD-ID", val((*args)[3], "UploadId"))
|
||||
|
||||
// CompleteMultipartUpload
|
||||
assert.Equal(t, "UPLOAD-ID", val((*args)[4], "UploadId"))
|
||||
assert.Equal(t, int64(1), val((*args)[4], "MultipartUpload.Parts[0].PartNumber"))
|
||||
assert.Equal(t, int64(2), val((*args)[4], "MultipartUpload.Parts[1].PartNumber"))
|
||||
assert.Equal(t, int64(3), val((*args)[4], "MultipartUpload.Parts[2].PartNumber"))
|
||||
assert.Regexp(t, `^ETAG\d+$`, val((*args)[4], "MultipartUpload.Parts[0].ETag"))
|
||||
assert.Regexp(t, `^ETAG\d+$`, val((*args)[4], "MultipartUpload.Parts[1].ETag"))
|
||||
assert.Regexp(t, `^ETAG\d+$`, val((*args)[4], "MultipartUpload.Parts[2].ETag"))
|
||||
|
||||
// Custom headers
|
||||
assert.Equal(t, "AES256", val((*args)[0], "ServerSideEncryption"))
|
||||
assert.Equal(t, "content/type", val((*args)[0], "ContentType"))
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiDifferentPartSize(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.PartSize = 1024 * 1024 * 7
|
||||
u.Concurrency = 1
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops)
|
||||
|
||||
// Part lengths
|
||||
assert.Equal(t, 1024*1024*7, buflen(val((*args)[1], "Body")))
|
||||
assert.Equal(t, 1024*1024*5, buflen(val((*args)[2], "Body")))
|
||||
}
|
||||
|
||||
func TestUploadIncreasePartSize(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
u.MaxUploadParts = 2
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(s3manager.DefaultDownloadPartSize), mgr.PartSize)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops)
|
||||
|
||||
// Part lengths
|
||||
assert.Equal(t, (1024*1024*6)+1, buflen(val((*args)[1], "Body")))
|
||||
assert.Equal(t, (1024*1024*6)-1, buflen(val((*args)[2], "Body")))
|
||||
}
|
||||
|
||||
func TestUploadFailIfPartSizeTooSmall(t *testing.T) {
|
||||
mgr := s3manager.NewUploader(unit.Session, func(u *s3manager.Uploader) {
|
||||
u.PartSize = 5
|
||||
})
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
})
|
||||
|
||||
assert.Nil(t, resp)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
aerr := err.(awserr.Error)
|
||||
assert.Equal(t, "ConfigError", aerr.Code())
|
||||
assert.Contains(t, aerr.Message(), "part size must be at least")
|
||||
}
|
||||
|
||||
func TestUploadOrderSingle(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf2MB),
|
||||
ServerSideEncryption: aws.String("AES256"),
|
||||
ContentType: aws.String("content/type"),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"PutObject"}, *ops)
|
||||
assert.NotEqual(t, "", resp.Location)
|
||||
assert.Equal(t, aws.String("VERSION-ID"), resp.VersionID)
|
||||
assert.Equal(t, "", resp.UploadID)
|
||||
assert.Equal(t, "AES256", val((*args)[0], "ServerSideEncryption"))
|
||||
assert.Equal(t, "content/type", val((*args)[0], "ContentType"))
|
||||
}
|
||||
|
||||
func TestUploadOrderSingleFailure(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
})
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf2MB),
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []string{"PutObject"}, *ops)
|
||||
assert.Nil(t, resp)
|
||||
}
|
||||
|
||||
func TestUploadOrderZero(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(make([]byte, 0)),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"PutObject"}, *ops)
|
||||
assert.NotEqual(t, "", resp.Location)
|
||||
assert.Equal(t, "", resp.UploadID)
|
||||
assert.Equal(t, 0, buflen(val((*args)[0], "Body")))
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiFailure(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
switch t := r.Data.(type) {
|
||||
case *s3.UploadPartOutput:
|
||||
if *t.ETag == "ETAG2" {
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "AbortMultipartUpload"}, *ops)
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiFailureOnComplete(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
switch r.Data.(type) {
|
||||
case *s3.CompleteMultipartUploadOutput:
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
}
|
||||
})
|
||||
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(buf12MB),
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart",
|
||||
"UploadPart", "CompleteMultipartUpload", "AbortMultipartUpload"}, *ops)
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiFailureOnCreate(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
switch r.Data.(type) {
|
||||
case *s3.CreateMultipartUploadOutput:
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
}
|
||||
})
|
||||
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(make([]byte, 1024*1024*12)),
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload"}, *ops)
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiFailureLeaveParts(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
switch data := r.Data.(type) {
|
||||
case *s3.UploadPartOutput:
|
||||
if *data.ETag == "ETAG2" {
|
||||
r.HTTPResponse.StatusCode = 400
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
u.LeavePartsOnError = true
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: bytes.NewReader(make([]byte, 1024*1024*12)),
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart"}, *ops)
|
||||
}
|
||||
|
||||
type failreader struct {
|
||||
times int
|
||||
failCount int
|
||||
}
|
||||
|
||||
func (f *failreader) Read(b []byte) (int, error) {
|
||||
f.failCount++
|
||||
if f.failCount >= f.times {
|
||||
return 0, fmt.Errorf("random failure")
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func TestUploadOrderReadFail1(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: &failreader{times: 1},
|
||||
})
|
||||
|
||||
assert.Equal(t, "ReadRequestBody", err.(awserr.Error).Code())
|
||||
assert.EqualError(t, err.(awserr.Error).OrigErr(), "random failure")
|
||||
assert.Equal(t, []string{}, *ops)
|
||||
}
|
||||
|
||||
func TestUploadOrderReadFail2(t *testing.T) {
|
||||
s, ops, _ := loggingSvc([]string{"UploadPart"})
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
})
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: &failreader{times: 2},
|
||||
})
|
||||
|
||||
assert.Equal(t, "ReadRequestBody", err.(awserr.Error).Code())
|
||||
assert.EqualError(t, err.(awserr.Error).OrigErr(), "random failure")
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "AbortMultipartUpload"}, *ops)
|
||||
}
|
||||
|
||||
type sizedReader struct {
|
||||
size int
|
||||
cur int
|
||||
}
|
||||
|
||||
func (s *sizedReader) Read(p []byte) (n int, err error) {
|
||||
if s.cur >= s.size {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n = len(p)
|
||||
s.cur += len(p)
|
||||
if s.cur > s.size {
|
||||
n -= s.cur - s.size
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiBufferedReader(t *testing.T) {
|
||||
s, ops, args := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
_, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: &sizedReader{size: 1024 * 1024 * 12},
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops)
|
||||
|
||||
// Part lengths
|
||||
parts := []int{
|
||||
buflen(val((*args)[1], "Body")),
|
||||
buflen(val((*args)[2], "Body")),
|
||||
buflen(val((*args)[3], "Body")),
|
||||
}
|
||||
sort.Ints(parts)
|
||||
assert.Equal(t, []int{1024 * 1024 * 2, 1024 * 1024 * 5, 1024 * 1024 * 5}, parts)
|
||||
}
|
||||
|
||||
func TestUploadOrderMultiBufferedReaderExceedTotalParts(t *testing.T) {
|
||||
s, ops, _ := loggingSvc([]string{"UploadPart"})
|
||||
mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
|
||||
u.Concurrency = 1
|
||||
u.MaxUploadParts = 2
|
||||
})
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: &sizedReader{size: 1024 * 1024 * 12},
|
||||
})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, resp)
|
||||
assert.Equal(t, []string{"CreateMultipartUpload", "AbortMultipartUpload"}, *ops)
|
||||
|
||||
aerr := err.(awserr.Error)
|
||||
assert.Equal(t, "TotalPartsExceeded", aerr.Code())
|
||||
assert.Contains(t, aerr.Message(), "configured MaxUploadParts (2)")
|
||||
}
|
||||
|
||||
func TestUploadOrderSingleBufferedReader(t *testing.T) {
|
||||
s, ops, _ := loggingSvc(emptyList)
|
||||
mgr := s3manager.NewUploaderWithClient(s)
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: &sizedReader{size: 1024 * 1024 * 2},
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"PutObject"}, *ops)
|
||||
assert.NotEqual(t, "", resp.Location)
|
||||
assert.Equal(t, "", resp.UploadID)
|
||||
}
|
||||
|
||||
func TestUploadZeroLenObject(t *testing.T) {
|
||||
requestMade := false
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requestMade = true
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
mgr := s3manager.NewUploaderWithClient(s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
}))
|
||||
resp, err := mgr.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String("Bucket"),
|
||||
Key: aws.String("Key"),
|
||||
Body: strings.NewReader(""),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, requestMade)
|
||||
assert.NotEqual(t, "", resp.Location)
|
||||
assert.Equal(t, "", resp.UploadID)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue