Vendor update github.com/pkg/errors

This commit is contained in:
Andrey Smirnov
2019-01-20 00:28:36 +03:00
parent 50f8cfbc15
commit 4b6c159e3a
20 changed files with 727 additions and 731 deletions

134
Gopkg.lock generated
View File

@@ -2,18 +2,23 @@
[[projects]]
digest = "1:e8777c437e157121465a08c05304d5847ae70b5683ef4afeb723b3c9e5e3bc67"
name = "github.com/AlekSi/pointer"
packages = ["."]
pruneopts = ""
revision = "08a25bac605b3fcb6cc27f3917b2c2c87451963d"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:218a66570875d243938fff08f17ec03e79b18c138d0845b2428bcb4929ffa4fe"
name = "github.com/DisposaBoy/JsonConfigReader"
packages = ["."]
pruneopts = ""
revision = "33a99fdf1d5ee1f79b5077e9c06f955ad356d5f4"
[[projects]]
digest = "1:658ab137074ef3d1216e01cbe166eb171a1bd77daeae0b686ab1ae184a9a5ec9"
name = "github.com/awalterschulze/gographviz"
packages = [
".",
@@ -22,10 +27,12 @@
"scanner",
"token"
]
pruneopts = ""
revision = "761fd5fbb34e4c2c138c280395b65b48e4ff5a53"
version = "v1.0"
[[projects]]
digest = "1:a72e35a51b628d148241720897de644fd6d3cea45d8489dae9d373ced5dfc302"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
@@ -56,155 +63,203 @@
"service/s3",
"service/sts"
]
pruneopts = ""
revision = "a72204b9bf8d48230ee0fe8995613b394c66f2da"
version = "v1.13.31"
[[projects]]
digest = "1:b9922c7da8a89c973758c03bde497017567f785b49bd253402a3587abec1e53d"
name = "github.com/cheggaaa/pb"
packages = ["."]
pruneopts = ""
revision = "cdf719fac0dd208251aa828e687c2d5802053b51"
version = "v1.0.10"
[[projects]]
branch = "master"
digest = "1:1120f960f5c334f0f94bad29eefaf73d52d226893369693686148f66c1993f15"
name = "github.com/gin-contrib/sse"
packages = ["."]
pruneopts = ""
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
[[projects]]
digest = "1:348ceb76f2ac958e541e4ba3190484b68df28c38ac9720ed4ef8d36af69ce52e"
name = "github.com/gin-gonic/gin"
packages = [
".",
"binding",
"render"
]
pruneopts = ""
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
version = "v1.2"
[[projects]]
digest = "1:fbed9ba4076145ae05ef7deeb14d49565e112d6c283a8c4304fa3b7be785fa5e"
name = "github.com/go-ini/ini"
packages = ["."]
pruneopts = ""
revision = "1730955e3146956d6a087861380f9b4667ed5071"
version = "v1.26.0"
[[projects]]
branch = "master"
digest = "1:27854310d59099f8dcc61dd8af4a69f0a3597f001154b2fb4d1c41baf2e31ec1"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = ""
revision = "130e6b02ab059e7b717a096f397c5b60111cae74"
[[projects]]
branch = "master"
digest = "1:09307dfb1aa3f49a2bf869dcfa4c6c06ecd3c207221bd1c1a1141f0e51f209eb"
name = "github.com/golang/snappy"
packages = ["."]
pruneopts = ""
revision = "553a641470496b2327abcac10b36396bd98e45c9"
[[projects]]
digest = "1:6ee50e0ace655f26787c120dbce51b3185c470f475c9e57d0dcada8ebb115004"
name = "github.com/h2non/filetype"
packages = ["matchers"]
pruneopts = ""
revision = "cc14fdc9ca0e4c2bafad7458f6ff79fd3947cfbb"
version = "v1.0.5"
[[projects]]
branch = "master"
digest = "1:64b78d98b8956492576911baf6a1e3499816d4575e485d12792e4abe7d8b6c46"
name = "github.com/jlaffaye/ftp"
packages = ["."]
pruneopts = ""
revision = "2403248fa8cc9f7909862627aa7337f13f8e0bf1"
[[projects]]
digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e"
name = "github.com/jmespath/go-jmespath"
packages = ["."]
pruneopts = ""
revision = "0b12d6b5"
[[projects]]
branch = "master"
digest = "1:c728183dd470c8bb2d1775edc641a81ec25f5e3804b8b0536e99f71df17a13a6"
name = "github.com/kjk/lzma"
packages = ["."]
pruneopts = ""
revision = "3fd93898850d5252457e48c1b3d5e1510597280b"
[[projects]]
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = ""
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
digest = "1:81e673df85e765593a863f67cba4544cf40e8919590f04d67664940786c2b61a"
name = "github.com/mattn/go-runewidth"
packages = ["."]
pruneopts = ""
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
digest = "1:fb8502ed69803c4cd97b1def119db73869ec2f7e2b408eb9c1b8276df6f05b3e"
name = "github.com/mattn/go-shellwords"
packages = ["."]
pruneopts = ""
revision = "005a0944d84452842197c2108bd9168ced206f78"
version = "v1.0.2"
[[projects]]
branch = "master"
digest = "1:3ba28ef4fbbf8d099c6227b698a6ceae28f8a071e12f06839c12c4c0003b7554"
name = "github.com/mkrautz/goar"
packages = ["."]
pruneopts = ""
revision = "282caa8bd9daba480b51f1d5a988714913b97aad"
[[projects]]
branch = "master"
digest = "1:d33ce379780d7c43405b9251289493cabada82f6bf9ab35eea6915d04f6ac8e0"
name = "github.com/mxk/go-flowrate"
packages = ["flowrate"]
pruneopts = ""
revision = "cca7078d478f8520f85629ad7c68962d31ed7682"
[[projects]]
branch = "master"
digest = "1:428d8af27f534ed06d783b03d477124796de06aa86402777cd2b494c64278da5"
name = "github.com/ncw/swift"
packages = [
".",
"swifttest"
]
pruneopts = ""
revision = "8e9b10220613abdbc2896808ee6b43e411a4fa6c"
[[projects]]
branch = "master"
digest = "1:beeb9206cc21cfeb113066c3dcf4bbb0ba304d73dd441f3244721566f51f44e6"
name = "github.com/pborman/uuid"
packages = ["."]
pruneopts = ""
revision = "c65b2f87fee37d1c7854c9164a450713c28d50cd"
[[projects]]
digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
pruneopts = ""
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
version = "v0.8.1"
[[projects]]
branch = "master"
digest = "1:c6e71685a14409c3a1fdbecef044ee6447c3887de7c2bb025ee12f9a8a368960"
name = "github.com/smira/commander"
packages = ["."]
pruneopts = ""
revision = "f408b00e68d5d6e21b9f18bd310978dafc604e47"
[[projects]]
branch = "master"
digest = "1:a75eb2e6e718988505f704d651eeb4734f0f0b580f761aa58b4a5b0afe585091"
name = "github.com/smira/flag"
packages = ["."]
pruneopts = ""
revision = "695ea5e84e76dea7c8656e43c384e54b32aa1b2a"
[[projects]]
branch = "master"
digest = "1:cd3b8057abbb453404cbef569951a7359986eedfc0a887f9bc5efff8d02e1760"
name = "github.com/smira/go-aws-auth"
packages = ["."]
revision = "0070896e9d7f4f9f2d558532b2d896ce2239992a"
pruneopts = ""
revision = "8b73995fd8d1d82519c7037ee243a497552cd54d"
[[projects]]
branch = "master"
digest = "1:7dd59b3536a07651baf394466da3b8a20bd3ed9ce1984c7583fdf2412fdcfea9"
name = "github.com/smira/go-ftp-protocol"
packages = ["protocol"]
pruneopts = ""
revision = "066b75c2b70dca7ae10b1b88b47534a3c31ccfaa"
[[projects]]
branch = "master"
digest = "1:55fe1086100b305a5562e9f1e6825ef97c49e82331cb0f055b2069f7c7ebd469"
name = "github.com/smira/go-xz"
packages = ["."]
pruneopts = ""
revision = "0c531f070014e218b21f3cfca801cc992d52726d"
[[projects]]
branch = "master"
name = "github.com/kjk/lzma"
packages = ["."]
revision = "3fd93898850d5252457e48c1b3d5e1510597280b"
[[projects]]
branch = "master"
digest = "1:175bc8d87d54849b9b9fc6cd473c5830e090fbf3c2f0ca71c7642a697e5d9237"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
@@ -220,21 +275,27 @@
"leveldb/table",
"leveldb/util"
]
pruneopts = ""
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
[[projects]]
digest = "1:b9bca27d5fbe4ad1a1802706629580ce923bb14255c51375480dff1bebcbb8b2"
name = "github.com/ugorji/go"
packages = ["codec"]
pruneopts = ""
revision = "71c2886f5a673a35f909803f38ece5810165097b"
[[projects]]
branch = "master"
digest = "1:2d8078b329a80bf4b71537dcd30853ff89fcafb611c94b2dfdb3d43ef1f23a1a"
name = "github.com/wsxiaoys/terminal"
packages = ["color"]
pruneopts = ""
revision = "0940f3fc43a0ed42d04916b1c04578462c650b09"
[[projects]]
branch = "master"
digest = "1:51aff2b69272cb95713b74675c0817e0a0caadc20337a8d9115bc68bf1105280"
name = "golang.org/x/crypto"
packages = [
"cast5",
@@ -247,44 +308,97 @@
"openpgp/s2k",
"ssh/terminal"
]
pruneopts = ""
revision = "b2aa35443fbc700ab74c586ae79b81c171851023"
[[projects]]
branch = "master"
digest = "1:267aa6124260d0e48d1ebf8bb84dce97caa133406b3caabc076cfc7a9e85ffe4"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
pruneopts = ""
revision = "1d206c9fa8975fb4cf00df1dc8bf3283dc24ba0e"
[[projects]]
branch = "v1"
digest = "1:e75566abfb876e81f00290ec153ff994c33bf8886134c1a38a9a9df5c15a2045"
name = "gopkg.in/check.v1"
packages = ["."]
pruneopts = ""
revision = "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec"
[[projects]]
digest = "1:dd549e360e5a8f982a28c2bcbe667307ceffe538ed9afc7c965524f1ac285b3f"
name = "gopkg.in/go-playground/validator.v8"
packages = ["."]
pruneopts = ""
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
version = "v8.18.2"
[[projects]]
digest = "1:0e886d5a5845f58255fb57bcb4a6aae7e1f9dd7c53defe7b87d57dd4cd127545"
name = "gopkg.in/h2non/filetype.v1"
packages = ["types"]
pruneopts = ""
revision = "3093b8ebec6efb56ac813238b8beab4ed4eaac6a"
version = "v1.0.1"
[[projects]]
branch = "v2"
digest = "1:81314a486195626940617e43740b4fa073f265b0715c9f54ce2027fee1cb5f61"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = ""
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "3ae43715f5d857c1686ad4b4310a5537afc8d0ab50dc658d11db7c2b36f17fee"
input-imports = [
"github.com/AlekSi/pointer",
"github.com/DisposaBoy/JsonConfigReader",
"github.com/awalterschulze/gographviz",
"github.com/aws/aws-sdk-go/aws",
"github.com/aws/aws-sdk-go/aws/awserr",
"github.com/aws/aws-sdk-go/aws/corehandlers",
"github.com/aws/aws-sdk-go/aws/credentials",
"github.com/aws/aws-sdk-go/aws/request",
"github.com/aws/aws-sdk-go/aws/session",
"github.com/aws/aws-sdk-go/service/s3",
"github.com/cheggaaa/pb",
"github.com/gin-gonic/gin",
"github.com/h2non/filetype/matchers",
"github.com/kjk/lzma",
"github.com/mattn/go-shellwords",
"github.com/mkrautz/goar",
"github.com/mxk/go-flowrate/flowrate",
"github.com/ncw/swift",
"github.com/ncw/swift/swifttest",
"github.com/pborman/uuid",
"github.com/pkg/errors",
"github.com/smira/commander",
"github.com/smira/flag",
"github.com/smira/go-aws-auth",
"github.com/smira/go-ftp-protocol/protocol",
"github.com/smira/go-xz",
"github.com/syndtr/goleveldb/leveldb",
"github.com/syndtr/goleveldb/leveldb/filter",
"github.com/syndtr/goleveldb/leveldb/opt",
"github.com/syndtr/goleveldb/leveldb/storage",
"github.com/syndtr/goleveldb/leveldb/util",
"github.com/ugorji/go/codec",
"github.com/wsxiaoys/terminal/color",
"golang.org/x/crypto/openpgp",
"golang.org/x/crypto/openpgp/armor",
"golang.org/x/crypto/openpgp/clearsign",
"golang.org/x/crypto/openpgp/errors",
"golang.org/x/crypto/openpgp/packet",
"golang.org/x/crypto/ssh/terminal",
"golang.org/x/sys/unix",
"gopkg.in/check.v1"
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,10 +1,14 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.3
- 1.5.4
- 1.6.2
- 1.7.1
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
script:

View File

@@ -1,4 +1,4 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
Package errors provides simple error handling primitives.
@@ -47,6 +47,6 @@ We welcome pull requests, bug fixes and issue reports. With that said, the bar f
Before proposing a change, please discuss your change by raising an issue.
## Licence
## License
BSD-2-Clause

View File

@@ -15,6 +15,7 @@ func noErrors(at, depth int) error {
}
return noErrors(at+1, depth)
}
func yesErrors(at, depth int) error {
if at >= depth {
return New("ye error")
@@ -22,8 +23,11 @@ func yesErrors(at, depth int) error {
return yesErrors(at+1, depth)
}
// GlobalE is an exported global to store the result of benchmark results,
// preventing the compiler from optimising the benchmark functions away.
var GlobalE error
func BenchmarkErrors(b *testing.B) {
var toperr error
type run struct {
stack int
std bool
@@ -53,7 +57,7 @@ func BenchmarkErrors(b *testing.B) {
err = f(0, r.stack)
}
b.StopTimer()
toperr = err
GlobalE = err
})
}
}

View File

@@ -6,7 +6,7 @@
// return err
// }
//
// which applied recursively up the call stack results in error reports
// which when applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
@@ -15,16 +15,17 @@
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
// together with the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
// If additional control is required, the errors.WithStack and
// errors.WithMessage functions destructure errors.Wrap into its component
// operations: annotating an error with a stack trace and with a message,
// respectively.
//
// Retrieving the cause of an error
//
@@ -38,7 +39,7 @@
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the topmost error that does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
@@ -48,16 +49,16 @@
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
// Although the causer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
// be formatted by the fmt package. The following verbs are supported:
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// printed recursively.
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
@@ -65,13 +66,13 @@
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
// invoked. This information can be retrieved with the following interface:
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
// The returned errors.StackTrace type is defined as
//
// type StackTrace []Frame
//
@@ -85,8 +86,8 @@
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
// Although the stackTracer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// See the documentation for Frame.Format for more details.
package errors
@@ -192,7 +193,7 @@ func Wrap(err error, message string) error {
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
@@ -220,6 +221,18 @@ func WithMessage(err error, message string) error {
}
}
// WithMessagef annotates err with the format specifier.
// If err is nil, WithMessagef returns nil.
func WithMessagef(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
}
type withMessage struct {
cause error
msg string

View File

@@ -196,7 +196,32 @@ func TestWithMessage(t *testing.T) {
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
}
}
}
func TestWithMessagefNil(t *testing.T) {
got := WithMessagef(nil, "no error")
if got != nil {
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWithMessagef(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{WithMessagef(io.EOF, "read error without format specifier"), "client error", "client error: read error without format specifier: EOF"},
{WithMessagef(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
}
for _, tt := range tests {
got := WithMessagef(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
}
}
}
// errors.New, etc values are not expected to be compared by value

View File

@@ -491,7 +491,7 @@ type wrapper struct {
want []string
}
func prettyBlocks(blocks []string, prefix ...string) string {
func prettyBlocks(blocks []string) string {
var out []string
for _, b := range blocks {

View File

@@ -46,7 +46,8 @@ func (f Frame) line() int {
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s path of source file relative to the compile time GOPATH
// %+s function name and path of source file relative to the compile time
// GOPATH separated by \n\t (<funcname>\n\t<path>)
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
@@ -79,6 +80,14 @@ func (f Frame) Format(s fmt.State, verb rune) {
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
@@ -136,43 +145,3 @@ func funcname(name string) string {
i = strings.Index(name, ".")
return name[i+1:]
}
func trimGOPATH(name, file string) string {
// Here we want to get the source file path relative to the compile time
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
// GOPATH at runtime, but we can infer the number of path segments in the
// GOPATH. We note that fn.Name() returns the function name qualified by
// the import path, which does not include the GOPATH. Thus we can trim
// segments from the beginning of the file path until the number of path
// separators remaining is one more than the number of path separators in
// the function name. For example, given:
//
// GOPATH /home/user
// file /home/user/src/pkg/sub/file.go
// fn.Name() pkg/sub.Type.Method
//
// We want to produce:
//
// pkg/sub/file.go
//
// From this we can easily see that fn.Name() has one less path separator
// than our desired output. We count separators from the end of the file
// path until it finds two more than in the function name and then move
// one character forward to preserve the initial path segment without a
// leading separator.
const sep = "/"
goal := strings.Count(name, sep) + 2
i := len(file)
for n := 0; n < goal; n++ {
i = strings.LastIndex(file[:i], sep)
if i == -1 {
// not enough separators found, set i so that the slice expression
// below leaves file unmodified
i = -len(sep)
break
}
}
// get back to 0 or trim the leading separator
file = file[i+len(sep):]
return file
}

View File

@@ -146,24 +146,6 @@ func TestFuncname(t *testing.T) {
}
}
func TestTrimGOPATH(t *testing.T) {
var tests = []struct {
Frame
want string
}{{
Frame(initpc),
"github.com/pkg/errors/stack_test.go",
}}
for i, tt := range tests {
pc := tt.Frame.pc()
fn := runtime.FuncForPC(pc)
file, _ := fn.FileLine(pc)
got := trimGOPATH(fn.Name(), file)
testFormatRegexp(t, i, got, "%s", tt.want)
}
}
func TestStackTrace(t *testing.T) {
tests := []struct {
err error
@@ -171,24 +153,24 @@ func TestStackTrace(t *testing.T) {
}{{
New("ooh"), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:172",
"\t.+/github.com/pkg/errors/stack_test.go:154",
},
}, {
Wrap(New("ooh"), "ahh"), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:177", // this is the stack of Wrap, not New
"\t.+/github.com/pkg/errors/stack_test.go:159", // this is the stack of Wrap, not New
},
}, {
Cause(Wrap(New("ooh"), "ahh")), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:182", // this is the stack of New
"\t.+/github.com/pkg/errors/stack_test.go:164", // this is the stack of New
},
}, {
func() error { return New("ooh") }(), []string{
`github.com/pkg/errors.(func·009|TestStackTrace.func1)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New
"\n\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New's caller
"\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New's caller
},
}, {
Cause(func() error {
@@ -197,11 +179,11 @@ func TestStackTrace(t *testing.T) {
}()
}()), []string{
`github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf
"\n\t.+/github.com/pkg/errors/stack_test.go:178", // this is the stack of Errorf
`github.com/pkg/errors.(func·011|TestStackTrace.func2)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller
"\n\t.+/github.com/pkg/errors/stack_test.go:179", // this is the stack of Errorf's caller
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
"\t.+/github.com/pkg/errors/stack_test.go:180", // this is the stack of Errorf's caller's caller
},
}}
for i, tt := range tests {
@@ -271,19 +253,19 @@ func TestStackTraceFormat(t *testing.T) {
}, {
stackTrace()[:2],
"%v",
`\[stack_test.go:225 stack_test.go:272\]`,
`\[stack_test.go:207 stack_test.go:254\]`,
}, {
stackTrace()[:2],
"%+v",
"\n" +
"github.com/pkg/errors.stackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:225\n" +
"\t.+/github.com/pkg/errors/stack_test.go:207\n" +
"github.com/pkg/errors.TestStackTraceFormat\n" +
"\t.+/github.com/pkg/errors/stack_test.go:276",
"\t.+/github.com/pkg/errors/stack_test.go:258",
}, {
stackTrace()[:2],
"%#v",
`\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`,
`\[\]errors.Frame{stack_test.go:207, stack_test.go:266}`,
}}
for i, tt := range tests {

1
vendor/github.com/smira/go-aws-auth/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
/.idea

12
vendor/github.com/smira/go-aws-auth/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# Contributing
In general, the code posted to the [SmartyStreets github organization](https://github.com/smartystreets) is created to solve specific problems at SmartyStreets that are ancillary to our core products in the address verification industry and may or may not be useful to other organizations or developers. Our reason for posting said code isn't necessarily to solicit feedback or contributions from the community but more as a showcase of some of the approaches to solving problems we have adopted.
Having stated that, we do consider issues raised by other githubbers as well as contributions submitted via pull requests. When submitting such a pull request, please follow these guidelines:
- _Look before you leap:_ If the changes you plan to make are significant, it's in everyone's best interest for you to discuss them with a SmartyStreets team member prior to opening a pull request.
- _License and ownership:_ If modifying the `LICENSE.md` file, limit your changes to fixing typographical mistakes. Do NOT modify the actual terms in the license or the copyright by **SmartyStreets, LLC**. Code submitted to SmartyStreets projects becomes property of SmartyStreets and must be compatible with the associated license.
- _Testing:_ If the code you are submitting resides in packages/modules covered by automated tests, be sure to add passing tests that cover your changes and assert expected behavior and state. Submit the additional test cases as part of your change set.
- _Style:_ Match your approach to **naming** and **formatting** with the surrounding code. Basically, the code you submit shouldn't stand out.
- "Naming" refers to such constructs as variables, methods, functions, classes, structs, interfaces, packages, modules, directories, files, etc...
- "Formatting" refers to such constructs as whitespace, horizontal line length, vertical function length, vertical file length, indentation, curly braces, etc...

View File

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

23
vendor/github.com/smira/go-aws-auth/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,23 @@
Copyright (c) 2016 SmartyStreets
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
NOTE: Various optional and subordinate components carry their own licensing
requirements and restrictions. Use of those components is subject to the terms
and conditions outlined the respective license of each component.

View File

@@ -192,15 +192,17 @@ const (
var (
awsSignVersion = map[string]int{
"autoscaling": 4,
"ce": 4,
"cloudfront": 4,
"cloudformation": 4,
"cloudsearch": 4,
"monitoring": 4,
"dynamodb": 4,
"ec2": 2,
"ec2": 4,
"elasticmapreduce": 4,
"elastictranscoder": 4,
"elasticache": 2,
"elasticache": 4,
"es": 4,
"glacier": 4,
"kinesis": 4,
"redshift": 4,
@@ -210,10 +212,10 @@ var (
"sqs": 4,
"s3": 4,
"elasticbeanstalk": 4,
"importexport": 2,
"importexport": 4,
"iam": 4,
"route53": 3,
"route53": 4,
"elasticloadbalancing": 4,
"email": 3,
"email": 4,
}
)

View File

@@ -9,246 +9,172 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/smartystreets/assertions"
"github.com/smartystreets/assertions/should"
"github.com/smartystreets/gunit"
)
func TestIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping long-running integration test.")
func TestIntegrationFixture(t *testing.T) {
if !credentialsSet() {
t.Skip("Required credentials absent from environment.")
}
Convey("Given real credentials from environment variables", t, func() {
Convey("A request (with out-of-order query string) with to IAM should succeed (assuming Administrator Access policy)", func() {
request := newRequest("GET", "https://iam.amazonaws.com/?Version=2010-05-08&Action=ListRoles", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign4AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to S3 should succeed", func() {
request, _ := http.NewRequest("GET", "https://s3.amazonaws.com", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign4AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to EC2 should succeed", func() {
request := newRequest("GET", "https://ec2.amazonaws.com/?Version=2013-10-15&Action=DescribeInstances", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign2AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to SQS should succeed", func() {
request := newRequest("POST", "https://sqs.us-west-2.amazonaws.com", url.Values{
"Action": []string{"ListQueues"},
})
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign4AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to SES should succeed", func() {
request := newRequest("GET", "https://email.us-east-1.amazonaws.com/?Action=GetSendStatistics", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign3AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to Route 53 should succeed", func() {
request := newRequest("GET", "https://route53.amazonaws.com/2013-04-01/hostedzone?maxitems=1", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign3AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("A request to SimpleDB should succeed", func() {
request := newRequest("GET", "https://sdb.amazonaws.com/?Action=ListDomains&Version=2009-04-15", nil)
if !credentialsSet() {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := sign2AndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
Convey("If S3Resource env variable is set", func() {
s3res := os.Getenv("S3Resource")
Convey("A URL-signed request to that S3 resource should succeed", func() {
request, _ := http.NewRequest("GET", s3res, nil)
if !credentialsSet() || s3res == "" {
SkipSo(http.StatusOK, ShouldEqual, http.StatusOK)
} else {
response := signS3UrlAndDo(request)
if response.StatusCode != http.StatusOK {
message, _ := ioutil.ReadAll(response.Body)
t.Error(string(message))
}
So(response.StatusCode, ShouldEqual, http.StatusOK)
}
})
})
})
gunit.RunSequential(new(IntegrationFixture), t)
}
func TestSign(t *testing.T) {
Convey("Requests to services using Version 2 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("GET", "https://ec2.amazonaws.com", url.Values{}),
newRequest("GET", "https://elasticache.amazonaws.com/", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request)
So(signedReq.URL.Query().Get("SignatureVersion"), ShouldEqual, "2")
}
})
type IntegrationFixture struct {
*gunit.Fixture
}
Convey("Requests to services using Version 3 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("GET", "https://route53.amazonaws.com", url.Values{}),
newRequest("GET", "https://email.us-east-1.amazonaws.com/", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request)
So(signedReq.Header.Get("X-Amzn-Authorization"), ShouldNotBeBlank)
}
})
func (this *IntegrationFixture) assertOK(response *http.Response) {
if !this.So(response.StatusCode, should.Equal, http.StatusOK) {
message, _ := ioutil.ReadAll(response.Body)
this.Error(string(message))
}
}
Convey("Requests to services using Version 4 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("POST", "https://sqs.amazonaws.com/", url.Values{}),
newRequest("GET", "https://iam.amazonaws.com", url.Values{}),
newRequest("GET", "https://s3.amazonaws.com", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request)
So(signedReq.Header.Get("Authorization"), ShouldContainSubstring, ", Signature=")
}
})
func (this *IntegrationFixture) LongTestSign4_IAM_OutOfOrderQueryString() {
request := newRequest("GET", "https://iam.amazonaws.com/?Version=2010-05-08&Action=ListRoles", nil)
response := sign4AndDo(request)
this.assertOK(response)
}
var keys Credentials
keys = newKeys()
Convey("Requests to services using existing credentials Version 2 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("GET", "https://ec2.amazonaws.com", url.Values{}),
newRequest("GET", "https://elasticache.amazonaws.com/", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request, keys)
So(signedReq.URL.Query().Get("SignatureVersion"), ShouldEqual, "2")
}
})
func (this *IntegrationFixture) LongTestSign4_S3() {
request, _ := http.NewRequest("GET", "https://s3.amazonaws.com", nil)
response := sign4AndDo(request)
this.assertOK(response)
}
Convey("Requests to services using existing credentials Version 3 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("GET", "https://route53.amazonaws.com", url.Values{}),
newRequest("GET", "https://email.us-east-1.amazonaws.com/", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request, keys)
So(signedReq.Header.Get("X-Amzn-Authorization"), ShouldNotBeBlank)
}
})
func (this *IntegrationFixture) LongTestSign2_EC2() {
request := newRequest("GET", "https://ec2.amazonaws.com/?Version=2013-10-15&Action=DescribeInstances", nil)
response := sign2AndDo(request)
this.assertOK(response)
}
func (this *IntegrationFixture) LongTestSign4_SQS() {
request := newRequest("POST", "https://sqs.us-west-2.amazonaws.com", url.Values{"Action": []string{"ListQueues"}})
response := sign4AndDo(request)
this.assertOK(response)
}
Convey("Requests to services using existing credentials Version 4 should be signed accordingly", t, func() {
reqs := []*http.Request{
newRequest("POST", "https://sqs.amazonaws.com/", url.Values{}),
newRequest("GET", "https://iam.amazonaws.com", url.Values{}),
newRequest("GET", "https://s3.amazonaws.com", url.Values{}),
}
for _, request := range reqs {
signedReq := Sign(request, keys)
So(signedReq.Header.Get("Authorization"), ShouldContainSubstring, ", Signature=")
}
})
func (this *IntegrationFixture) LongTestSign3_SES() {
request := newRequest("GET", "https://email.us-east-1.amazonaws.com/?Action=GetSendStatistics", nil)
response := sign3AndDo(request)
this.assertOK(response)
}
func (this *IntegrationFixture) LongTestSign3_Route53() {
request := newRequest("GET", "https://route53.amazonaws.com/2013-04-01/hostedzone?maxitems=1", nil)
response := sign3AndDo(request)
this.assertOK(response)
}
func (this *IntegrationFixture) LongTestSign2_SimpleDB() {
request := newRequest("GET", "https://sdb.amazonaws.com/?Action=ListDomains&Version=2009-04-15", nil)
response := sign2AndDo(request)
this.assertOK(response)
}
func (this *IntegrationFixture) LongTestSignS3Url() {
s3res := os.Getenv("S3Resource")
if s3res == "" {
return
}
request, _ := http.NewRequest("GET", s3res, nil)
response := signS3UrlAndDo(request)
this.assertOK(response)
}
func TestSign_Version2(t *testing.T) {
requests := []*http.Request{
newRequest("GET", "https://ec2.amazonaws.com", url.Values{}),
newRequest("GET", "https://elasticache.amazonaws.com/", url.Values{}),
}
for _, request := range requests {
signed := Sign(request)
assertions.New(t).So(signed.URL.Query().Get("SignatureVersion"), should.Equal, "2")
}
}
func TestSign_Version3(t *testing.T) {
requests := []*http.Request{
newRequest("GET", "https://route53.amazonaws.com", url.Values{}),
newRequest("GET", "https://email.us-east-1.amazonaws.com/", url.Values{}),
}
for _, request := range requests {
signed := Sign(request)
assertions.New(t).So(signed.Header.Get("X-Amzn-Authorization"), should.NotBeBlank)
}
}
func TestSign_Version4(t *testing.T) {
requests := []*http.Request{
newRequest("POST", "https://sqs.amazonaws.com/", url.Values{}),
newRequest("GET", "https://iam.amazonaws.com", url.Values{}),
newRequest("GET", "https://s3.amazonaws.com", url.Values{}),
}
for _, request := range requests {
signed := Sign(request)
assertions.New(t).So(signed.Header.Get("Authorization"), should.ContainSubstring, ", Signature=")
}
}
func TestSign_ExistingCredentials_Version2(t *testing.T) {
requests := []*http.Request{
newRequest("GET", "https://ec2.amazonaws.com", url.Values{}),
newRequest("GET", "https://elasticache.amazonaws.com/", url.Values{}),
}
for _, request := range requests {
signed := Sign(request, newKeys())
assertions.New(t).So(signed.URL.Query().Get("SignatureVersion"), should.Equal, "2")
}
}
func TestSign_ExistingCredentials_Version3(t *testing.T) {
requests := []*http.Request{
newRequest("GET", "https://route53.amazonaws.com", url.Values{}),
newRequest("GET", "https://email.us-east-1.amazonaws.com/", url.Values{}),
}
for _, request := range requests {
signed := Sign(request, newKeys())
assertions.New(t).So(signed.Header.Get("X-Amzn-Authorization"), should.NotBeBlank)
}
}
func TestSign_ExistingCredentials_Version4(t *testing.T) {
requests := []*http.Request{
newRequest("POST", "https://sqs.amazonaws.com/", url.Values{}),
newRequest("GET", "https://iam.amazonaws.com", url.Values{}),
newRequest("GET", "https://s3.amazonaws.com", url.Values{}),
}
for _, request := range requests {
signed := Sign(request, newKeys())
assertions.New(t).So(signed.Header.Get("Authorization"), should.ContainSubstring, ", Signature=")
}
}
func TestExpiration(t *testing.T) {
assert := assertions.New(t)
var credentials = &Credentials{}
Convey("Credentials without an expiration can't expire", t, func() {
So(credentials.expired(), ShouldBeFalse)
})
// Credentials without an expiration can't expire
assert.So(credentials.expired(), should.BeFalse)
Convey("Credentials that expire in 5 minutes aren't expired", t, func() {
credentials.Expiration = time.Now().Add(5 * time.Minute)
So(credentials.expired(), ShouldBeFalse)
})
// Credentials that expire in 5 minutes aren't expired
credentials.Expiration = time.Now().Add(5 * time.Minute)
assert.So(credentials.expired(), should.BeFalse)
Convey("Credentials that expire in 1 minute are expired", t, func() {
credentials.Expiration = time.Now().Add(1 * time.Minute)
So(credentials.expired(), ShouldBeTrue)
})
// Credentials that expire in 1 minute are expired
credentials.Expiration = time.Now().Add(1 * time.Minute)
assert.So(credentials.expired(), should.BeTrue)
Convey("Credentials that expired 2 hours ago are expired", t, func() {
credentials.Expiration = time.Now().Add(-2 * time.Hour)
So(credentials.expired(), ShouldBeTrue)
})
// Credentials that expired 2 hours ago are expired
credentials.Expiration = time.Now().Add(-2 * time.Hour)
assert.So(credentials.expired(), should.BeTrue)
}
func credentialsSet() bool {
var keys Credentials
keys = newKeys()
if keys.AccessKeyID == "" {
return false
} else {
return true
}
return keys.AccessKeyID != ""
}
func newRequest(method string, url string, v url.Values) *http.Request {

View File

@@ -4,86 +4,66 @@ import (
"net/url"
"testing"
. "github.com/smartystreets/goconvey/convey"
"github.com/smartystreets/assertions/should"
"github.com/smartystreets/gunit"
)
func TestCommonFunctions(t *testing.T) {
Convey("Service and region should be properly extracted from host strings", t, func() {
service, region := serviceAndRegion("sqs.us-west-2.amazonaws.com")
So(service, ShouldEqual, "sqs")
So(region, ShouldEqual, "us-west-2")
service, region = serviceAndRegion("iam.amazonaws.com")
So(service, ShouldEqual, "iam")
So(region, ShouldEqual, "us-east-1")
service, region = serviceAndRegion("sns.us-west-2.amazonaws.com")
So(service, ShouldEqual, "sns")
So(region, ShouldEqual, "us-west-2")
service, region = serviceAndRegion("bucketname.s3.amazonaws.com")
So(service, ShouldEqual, "s3")
So(region, ShouldEqual, "us-east-1")
service, region = serviceAndRegion("s3.amazonaws.com")
So(service, ShouldEqual, "s3")
So(region, ShouldEqual, "us-east-1")
service, region = serviceAndRegion("s3-us-west-1.amazonaws.com")
So(service, ShouldEqual, "s3")
So(region, ShouldEqual, "us-west-1")
service, region = serviceAndRegion("s3-external-1.amazonaws.com")
So(service, ShouldEqual, "s3")
So(region, ShouldEqual, "us-east-1")
})
Convey("MD5 hashes should be properly computed and base-64 encoded", t, func() {
input := []byte("Pretend this is a REALLY long byte array...")
actual := hashMD5(input)
So(actual, ShouldEqual, "KbVTY8Vl6VccnzQf1AGOFw==")
})
Convey("SHA-256 hashes should be properly hex-encoded (base 16)", t, func() {
input := []byte("This is... Sparta!!")
actual := hashSHA256(input)
So(actual, ShouldEqual, "5c81a4ef1172e89b1a9d575f4cd82f4ed20ea9137e61aa7f1ab936291d24e79a")
})
Convey("Given a key and contents", t, func() {
key := []byte("asdf1234")
contents := "SmartyStreets was here"
Convey("HMAC-SHA256 should be properly computed", func() {
expected := []byte{65, 46, 186, 78, 2, 155, 71, 104, 49, 37, 5, 66, 195, 129, 159, 227, 239, 53, 240, 107, 83, 21, 235, 198, 238, 216, 108, 149, 143, 222, 144, 94}
actual := hmacSHA256(key, contents)
So(actual, ShouldResemble, expected)
})
Convey("HMAC-SHA1 should be properly computed", func() {
expected := []byte{164, 77, 252, 0, 87, 109, 207, 110, 163, 75, 228, 122, 83, 255, 233, 237, 125, 206, 85, 70}
actual := hmacSHA1(key, contents)
So(actual, ShouldResemble, expected)
})
})
Convey("Strings should be properly concatenated with a delimiter", t, func() {
So(concat("\n", "Test1", "Test2"), ShouldEqual, "Test1\nTest2")
So(concat(".", "Test1"), ShouldEqual, "Test1")
So(concat("\t", "1", "2", "3", "4"), ShouldEqual, "1\t2\t3\t4")
})
Convey("URI components should be properly encoded", t, func() {
So(normuri("/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), ShouldEqual, "/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
So(normuri("/ /foo"), ShouldEqual, "/%20/foo")
So(normuri("/(foo)"), ShouldEqual, "/%28foo%29")
})
Convey("URI query strings should be properly encoded", t, func() {
So(normquery(url.Values{"p": []string{" +&;-=._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}}), ShouldEqual, "p=%20%2B%26%3B-%3D._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
})
func TestCommonFixture(t *testing.T) {
gunit.Run(new(CommonFixture), t)
}
type CommonFixture struct {
*gunit.Fixture
}
func (this *CommonFixture) serviceAndRegion(id string) []string {
service, region := serviceAndRegion(id)
return []string{service, region}
}
func (this *CommonFixture) TestServiceAndRegion() {
this.So(this.serviceAndRegion("sqs.us-west-2.amazonaws.com"), should.Resemble, []string{"sqs", "us-west-2"})
this.So(this.serviceAndRegion("iam.amazonaws.com"), should.Resemble, []string{"iam", "us-east-1"})
this.So(this.serviceAndRegion("sns.us-west-2.amazonaws.com"), should.Resemble, []string{"sns", "us-west-2"})
this.So(this.serviceAndRegion("bucketname.s3.amazonaws.com"), should.Resemble, []string{"s3", "us-east-1"})
this.So(this.serviceAndRegion("s3.amazonaws.com"), should.Resemble, []string{"s3", "us-east-1"})
this.So(this.serviceAndRegion("s3-us-west-1.amazonaws.com"), should.Resemble, []string{"s3", "us-west-1"})
this.So(this.serviceAndRegion("s3-external-1.amazonaws.com"), should.Resemble, []string{"s3", "us-east-1"})
}
func (this *CommonFixture) TestHashFunctions() {
this.So(hashMD5([]byte("Pretend this is a REALLY long byte array...")), should.Equal, "KbVTY8Vl6VccnzQf1AGOFw==")
this.So(hashSHA256([]byte("This is... Sparta!!")), should.Equal,
"5c81a4ef1172e89b1a9d575f4cd82f4ed20ea9137e61aa7f1ab936291d24e79a")
key := []byte("asdf1234")
contents := "SmartyStreets was here"
expectedHMAC_SHA256 := []byte{
65, 46, 186, 78, 2, 155, 71, 104, 49, 37, 5, 66, 195, 129, 159, 227,
239, 53, 240, 107, 83, 21, 235, 198, 238, 216, 108, 149, 143, 222, 144, 94}
this.So(hmacSHA256(key, contents), should.Resemble, expectedHMAC_SHA256)
expectedHMAC_SHA1 := []byte{
164, 77, 252, 0, 87, 109, 207, 110, 163, 75, 228, 122, 83, 255, 233, 237, 125, 206, 85, 70}
this.So(hmacSHA1(key, contents), should.Resemble, expectedHMAC_SHA1)
}
func (this *CommonFixture) TestConcat() {
this.So(concat("\n", "Test1", "Test2"), should.Equal, "Test1\nTest2")
this.So(concat(".", "Test1"), should.Equal, "Test1")
this.So(concat("\t", "1", "2", "3", "4"), should.Equal, "1\t2\t3\t4")
}
func (this *CommonFixture) TestURINormalization() {
this.So(
normuri("/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), should.Equal,
"/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
this.So(normuri("/ /foo"), should.Equal, "/%20/foo")
this.So(normuri("/(foo)"), should.Equal, "/%28foo%29")
this.So(
normquery(url.Values{"p": []string{" +&;-=._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}}),
should.Equal,
"p=%20%2B%26%3B-%3D._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
}

View File

@@ -7,99 +7,98 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"net/http/httptest"
"github.com/smartystreets/assertions"
"github.com/smartystreets/assertions/should"
"github.com/smartystreets/gunit"
)
func TestSignatureS3(t *testing.T) {
// http://docs.aws.amazon.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html
// Note: S3 now supports signed signature version 4
// (but signed URL requests still utilize a lot of the same functionality)
// http://docs.aws.amazon.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html
// Note: S3 now supports signed signature version 4
// (but signed URL requests still utilize a lot of the same functionality)
Convey("Given a GET request to Amazon S3", t, func() {
keys := *testCredS3
request := test_plainRequestS3()
func TestSignatureS3Fixture(t *testing.T) {
gunit.RunSequential(new(SignatureS3Fixture), t)
}
// Mock time
now = func() time.Time {
parsed, _ := time.Parse(timeFormatS3, exampleReqTsS3)
return parsed
}
type SignatureS3Fixture struct {
*gunit.Fixture
Convey("The request should be prepared with a Date header", func() {
prepareRequestS3(request)
So(request.Header.Get("Date"), ShouldEqual, exampleReqTsS3)
})
keys Credentials
request *http.Request
}
Convey("The CanonicalizedAmzHeaders should be built properly", func() {
req2 := test_headerRequestS3()
actual := canonicalAmzHeadersS3(req2)
So(actual, ShouldEqual, expectedCanonAmzHeadersS3)
})
func (this *SignatureS3Fixture) Setup() {
this.keys = *testCredS3
this.request = test_plainRequestS3()
Convey("The CanonicalizedResource should be built properly", func() {
actual := canonicalResourceS3(request)
So(actual, ShouldEqual, expectedCanonResourceS3)
})
now = func() time.Time {
parsed, _ := time.Parse(timeFormatS3, exampleReqTsS3)
return parsed
}
}
Convey("The string to sign should be correct", func() {
actual := stringToSignS3(request)
So(actual, ShouldEqual, expectedStringToSignS3)
})
func (this *SignatureS3Fixture) TestRequestShouldHaveADateHeader() {
prepareRequestS3(this.request)
this.So(this.request.Header.Get("Date"), should.Equal, exampleReqTsS3)
}
Convey("The final signature string should be exactly correct", func() {
actual := signatureS3(stringToSignS3(request), keys)
So(actual, ShouldEqual, "bWq2s1WEIj+Ydj0vQ697zp+IXMU=")
})
})
func (this *SignatureS3Fixture) TestRequestShouldHaveCanonicalizedAmzHeaders() {
req2 := test_headerRequestS3()
actual := canonicalAmzHeadersS3(req2)
this.So(actual, should.Equal, expectedCanonAmzHeadersS3)
}
Convey("Given a GET request for a resource on S3 for query string authentication", t, func() {
keys := *testCredS3
request, _ := http.NewRequest("GET", "https://johnsmith.s3.amazonaws.com/johnsmith/photos/puppy.jpg", nil)
func (this *SignatureS3Fixture) TestCanonicalizedResourceBuiltProperly() {
actual := canonicalResourceS3(this.request)
this.So(actual, should.Equal, expectedCanonResourceS3)
}
now = func() time.Time {
parsed, _ := time.Parse(timeFormatS3, exampleReqTsS3)
return parsed
}
func (this *SignatureS3Fixture) TestStringToSignShouldBeCorrect() {
actual := stringToSignS3(this.request)
this.So(actual, should.Equal, expectedStringToSignS3)
}
Convey("The string to sign should be correct", func() {
actual := stringToSignS3Url("GET", now(), request.URL.Path)
So(actual, ShouldEqual, expectedStringToSignS3Url)
})
func (this *SignatureS3Fixture) TestFinalSignatureShouldBeExactlyCorrect() {
actual := signatureS3(stringToSignS3(this.request), this.keys)
this.So(actual, should.Equal, "bWq2s1WEIj+Ydj0vQ697zp+IXMU=")
}
Convey("The signature of string to sign should be correct", func() {
actual := signatureS3(expectedStringToSignS3Url, keys)
So(actual, ShouldEqual, "R2K/+9bbnBIbVDCs7dqlz3XFtBQ=")
})
func (this *SignatureS3Fixture) TestQueryStringAuthentication() {
this.request = httptest.NewRequest("GET", "https://johnsmith.s3.amazonaws.com/johnsmith/photos/puppy.jpg", nil)
Convey("The finished signed URL should be correct", func() {
expiry := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
So(SignS3Url(request, expiry, keys).URL.String(), ShouldEqual, expectedSignedS3Url)
})
})
// The string to sign should be correct
actual := stringToSignS3Url("GET", now(), this.request.URL.Path)
this.So(actual, should.Equal, expectedStringToSignS3Url)
// The signature of string to sign should be correct
actualSignature := signatureS3(expectedStringToSignS3Url, this.keys)
this.So(actualSignature, should.Equal, "R2K/+9bbnBIbVDCs7dqlz3XFtBQ=")
// The finished signed URL should be correct
expiry := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
this.So(SignS3Url(this.request, expiry, this.keys).URL.String(), should.Equal, expectedSignedS3Url)
}
func TestS3STSRequestPreparer(t *testing.T) {
Convey("Given a plain request with no custom headers", t, func() {
request := test_plainRequestS3()
// Given a plain request with no custom headers
request := test_plainRequestS3()
Convey("And a set of credentials with an STS token", func() {
keys := *testCredS3WithSTS
// And a set of credentials with an STS token
keys := *testCredS3WithSTS
Convey("It should include an X-Amz-Security-Token when the request is signed", func() {
actualSigned := SignS3(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
// It should include an X-Amz-Security-Token when the request is signed
actualSigned := SignS3(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
So(actual, ShouldNotBeBlank)
So(actual, ShouldEqual, testCredS3WithSTS.SecurityToken)
})
})
})
assert := assertions.New(t)
assert.So(actual, should.NotBeBlank)
assert.So(actual, should.Equal, testCredS3WithSTS.SecurityToken)
}
func test_plainRequestS3() *http.Request {
request, _ := http.NewRequest("GET", "https://johnsmith.s3.amazonaws.com/photos/puppy.jpg", nil)
return request
return httptest.NewRequest("GET", "https://johnsmith.s3.amazonaws.com/photos/puppy.jpg", nil)
}
func test_headerRequestS3() *http.Request {

View File

@@ -6,82 +6,68 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/smartystreets/assertions"
"github.com/smartystreets/assertions/should"
"github.com/smartystreets/gunit"
)
func TestSignature2(t *testing.T) {
// http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
// http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
Convey("Given bogus credentials", t, func() {
keys := *testCredV2
func TestSignature2Fixture(t *testing.T) {
gunit.RunSequential(new(Signature2Fixture), t)
}
// Mock time
now = func() time.Time {
parsed, _ := time.Parse(timeFormatV2, exampleReqTsV2)
return parsed
}
type Signature2Fixture struct {
*gunit.Fixture
Convey("Given a plain request that is unprepared", func() {
request := test_plainRequestV2()
keys Credentials
}
Convey("The request should be prepared to be signed", func() {
expectedUnsigned := test_unsignedRequestV2()
prepareRequestV2(request, keys)
So(request, ShouldResemble, expectedUnsigned)
})
})
func (this *Signature2Fixture) Setup() {
this.keys = *testCredV2
Convey("Given a prepared, but unsigned, request", func() {
request := test_unsignedRequestV2()
// Mock time
now = func() time.Time {
parsed, _ := time.Parse(timeFormatV2, exampleReqTsV2)
return parsed
}
}
Convey("The canonical query string should be correct", func() {
actual := canonicalQueryStringV2(request)
expected := canonicalQsV2
So(actual, ShouldEqual, expected)
})
func (this *Signature2Fixture) TestSignUnpreparedPlanRequest() {
request := test_plainRequestV2()
prepareRequestV2(request, this.keys)
this.So(request, should.Resemble, test_unsignedRequestV2())
}
Convey("The absolute path should be extracted correctly", func() {
So(request.URL.Path, ShouldEqual, "/")
})
func (this *Signature2Fixture) TestSignPreparedUnsignedRequest() {
request := test_unsignedRequestV2()
actual := canonicalQueryStringV2(request)
expected := canonicalQsV2
this.So(actual, should.Equal, expected)
this.So(request.URL.Path, should.Equal, "/")
Convey("The string to sign should be well-formed", func() {
actual := stringToSignV2(request)
So(actual, ShouldEqual, expectedStringToSignV2)
})
this.So(stringToSignV2(request), should.Equal, expectedStringToSignV2)
this.So(signatureV2(stringToSignV2(request), this.keys), should.Equal, "i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf/Mj6vPxyYIs=")
Convey("The resulting signature should be correct", func() {
actual := signatureV2(stringToSignV2(request), keys)
So(actual, ShouldEqual, "i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf/Mj6vPxyYIs=")
})
Convey("The final signed request should be correctly formed", func() {
Sign2(request, keys)
actual := request.URL.String()
So(actual, ShouldResemble, expectedFinalUrlV2)
})
})
})
Sign2(request, this.keys)
this.So(request.URL.String(), should.Equal, expectedFinalUrlV2)
}
func TestVersion2STSRequestPreparer(t *testing.T) {
Convey("Given a plain request ", t, func() {
request := test_plainRequestV2()
// Given a plain request
request := test_plainRequestV2()
Convey("And a set of credentials with an STS token", func() {
var keys Credentials
keys = *testCredV2WithSTS
// And a set of credentials with an STS token
var keys Credentials
keys = *testCredV2WithSTS
Convey("It should include the SecurityToken parameter when the request is signed", func() {
actualSigned := Sign2(request, keys)
actual := actualSigned.URL.Query()["SecurityToken"][0]
So(actual, ShouldNotBeBlank)
So(actual, ShouldEqual, testCredV2WithSTS.SecurityToken)
})
})
})
// It should include the SecurityToken parameter when the request is signed
actualSigned := Sign2(request, keys)
actual := actualSigned.URL.Query()["SecurityToken"][0]
assert := assertions.New(t)
assert.So(actual, should.NotBeBlank)
assert.So(actual, should.Equal, testCredV2WithSTS.SecurityToken)
}
func test_plainRequestV2() *http.Request {
@@ -89,9 +75,9 @@ func test_plainRequestV2() *http.Request {
values.Set("Action", "DescribeJobFlows")
values.Set("Version", "2009-03-31")
url := baseUrlV2 + "?" + values.Encode()
address := baseUrlV2 + "?" + values.Encode()
request, err := http.NewRequest("GET", url, nil)
request, err := http.NewRequest("GET", address, nil)
if err != nil {
panic(err)
}

View File

@@ -6,56 +6,48 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/smartystreets/assertions"
"github.com/smartystreets/assertions/should"
)
func TestSignature3(t *testing.T) {
// http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/RESTAuthentication.html
// http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-authentication.html
Convey("Given bogus credentials", t, func() {
keys := *testCredV3
assert := assertions.New(t)
// Mock time
now = func() time.Time {
parsed, _ := time.Parse(timeFormatV3, exampleReqTsV3)
return parsed
}
// Given bogus credentials
keys := *testCredV3
Convey("Given a plain request that is unprepared", func() {
request := test_plainRequestV3()
// Mock time
now = func() time.Time {
parsed, _ := time.Parse(timeFormatV3, exampleReqTsV3)
return parsed
}
Convey("The request should be prepared to be signed", func() {
expectedUnsigned := test_unsignedRequestV3()
prepareRequestV3(request)
So(request, ShouldResemble, expectedUnsigned)
})
})
// Given a plain request that is unprepared
request := test_plainRequestV3()
Convey("Given a prepared, but unsigned, request", func() {
request := test_unsignedRequestV3()
// The request should be prepared to be signed
expectedUnsigned := test_unsignedRequestV3()
prepareRequestV3(request)
assert.So(request, should.Resemble, expectedUnsigned)
Convey("The absolute path should be extracted correctly", func() {
So(request.URL.Path, ShouldEqual, "/")
})
// Given a prepared, but unsigned, request
request = test_unsignedRequestV3()
Convey("The string to sign should be well-formed", func() {
actual := stringToSignV3(request)
So(actual, ShouldEqual, expectedStringToSignV3)
})
// The absolute path should be extracted correctly
assert.So(request.URL.Path, should.Equal, "/")
Convey("The resulting signature should be correct", func() {
actual := signatureV3(stringToSignV3(request), keys)
So(actual, ShouldEqual, "PjAJ6buiV6l4WyzmmuwtKE59NJXVg5Dr3Sn4PCMZ0Yk=")
})
// The string to sign should be well-formed
assert.So(stringToSignV3(request), should.Equal, expectedStringToSignV3)
Convey("The final signed request should be correctly formed", func() {
Sign3(request, keys)
actual := request.Header.Get("X-Amzn-Authorization")
So(actual, ShouldResemble, expectedAuthHeaderV3)
})
})
})
// The resulting signature should be correct
assert.So(signatureV3(stringToSignV3(request), keys), should.Equal, "PjAJ6buiV6l4WyzmmuwtKE59NJXVg5Dr3Sn4PCMZ0Yk=")
// The final signed request should be correctly formed
Sign3(request, keys)
assert.So(request.Header.Get("X-Amzn-Authorization"), should.Resemble, expectedAuthHeaderV3)
}
func test_plainRequestV3() *http.Request {
@@ -63,9 +55,9 @@ func test_plainRequestV3() *http.Request {
values.Set("Action", "GetSendStatistics")
values.Set("Version", "2010-12-01")
url := baseUrlV3 + "/?" + values.Encode()
address := baseUrlV3 + "/?" + values.Encode()
request, err := http.NewRequest("GET", url, nil)
request, err := http.NewRequest("GET", address, nil)
if err != nil {
panic(err)
}
@@ -83,23 +75,20 @@ func test_unsignedRequestV3() *http.Request {
}
func TestVersion3STSRequestPreparer(t *testing.T) {
Convey("Given a plain request with no custom headers", t, func() {
request := test_plainRequestV3()
// Given a plain request with no custom headers
request := test_plainRequestV3()
Convey("And a set of credentials with an STS token", func() {
var keys Credentials
keys = *testCredV3WithSTS
// And a set of credentials with an STS token
var keys Credentials
keys = *testCredV3WithSTS
Convey("It should include an X-Amz-Security-Token when the request is signed", func() {
actualSigned := Sign3(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
// It should include an X-Amz-Security-Token when the request is signed
actualSigned := Sign3(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
So(actual, ShouldNotBeBlank)
So(actual, ShouldEqual, testCredV4WithSTS.SecurityToken)
})
})
})
assert := assertions.New(t)
assert.So(actual, should.NotBeBlank)
assert.So(actual, should.Equal, testCredV4WithSTS.SecurityToken)
}

View File

@@ -2,173 +2,155 @@ package awsauth
import (
"net/http"
"net/http/httputil"
"net/url"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
"github.com/smartystreets/assertions"
"github.com/smartystreets/assertions/should"
)
func TestVersion4RequestPreparer(t *testing.T) {
Convey("Given a plain request with no custom headers", t, func() {
request := test_plainRequestV4(false)
func TestVersion4RequestPreparer_1(t *testing.T) {
// Given a plain request with no custom headers
request := test_plainRequestV4(false)
prepareRequestV4(request)
expectedUnsigned := test_unsignedRequestV4(true, false)
expectedUnsigned.Header.Set("X-Amz-Date", timestampV4())
expectedUnsigned := test_unsignedRequestV4(true, false)
expectedUnsigned.Header.Set("X-Amz-Date", timestampV4())
Convey("The necessary, default headers should be appended", func() {
prepareRequestV4(request)
So(request, ShouldResemble, expectedUnsigned)
})
assert := assertions.New(t)
Convey("Forward-slash should be appended to URI if not present", func() {
prepareRequestV4(request)
So(request.URL.Path, ShouldEqual, "/")
})
// The necessary, default headers should be appended
assert.So(dumpRequest(request), should.Equal, dumpRequest(expectedUnsigned))
Convey("And a set of credentials", func() {
var keys Credentials
keys = *testCredV4
// Forward-slash should be appended to URI if not present
assert.So(request.URL.Path, should.Equal, "/")
}
Convey("It should be signed with an Authorization header", func() {
actualSigned := Sign4(request, keys)
actual := actualSigned.Header.Get("Authorization")
func TestVersion4RequestPreparer_2(t *testing.T) {
// And a set of credentials
// It should be signed with an Authorization header
request := test_plainRequestV4(false)
actualSigned := Sign4(request, *testCredV4)
actual := actualSigned.Header.Get("Authorization")
So(actual, ShouldNotBeBlank)
So(actual, ShouldContainSubstring, "Credential="+testCredV4.AccessKeyID)
So(actual, ShouldContainSubstring, "SignedHeaders=")
So(actual, ShouldContainSubstring, "Signature=")
So(actual, ShouldContainSubstring, "AWS4")
})
})
})
assert := assertions.New(t)
assert.So(actual, should.NotBeBlank)
assert.So(actual, should.ContainSubstring, "Credential="+testCredV4.AccessKeyID)
assert.So(actual, should.ContainSubstring, "SignedHeaders=")
assert.So(actual, should.ContainSubstring, "Signature=")
assert.So(actual, should.ContainSubstring, "AWS4")
}
Convey("Given a request with custom, necessary headers", t, func() {
Convey("The custom, necessary headers must not be changed", func() {
request := test_unsignedRequestV4(true, false)
prepareRequestV4(request)
So(request, ShouldResemble, test_unsignedRequestV4(true, false))
})
})
func TestVersion4RequestPreparer_3(t *testing.T) {
// Given a request with custom, necessary headers
// The custom, necessary headers must not be changed
request := test_unsignedRequestV4(true, false)
prepareRequestV4(request)
assertions.New(t).So(dumpRequest(request), should.Equal, dumpRequest(test_unsignedRequestV4(true, false)))
}
func TestVersion4STSRequestPreparer(t *testing.T) {
Convey("Given a plain request with no custom headers", t, func() {
request := test_plainRequestV4(false)
// Given a plain request with no custom headers
request := test_plainRequestV4(false)
Convey("And a set of credentials with an STS token", func() {
var keys Credentials
keys = *testCredV4WithSTS
// And a set of credentials with an STS token
var keys Credentials
keys = *testCredV4WithSTS
Convey("It should include an X-Amz-Security-Token when the request is signed", func() {
actualSigned := Sign4(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
So(actual, ShouldNotBeBlank)
So(actual, ShouldEqual, testCredV4WithSTS.SecurityToken)
})
})
})
// It should include an X-Amz-Security-Token when the request is signed
actualSigned := Sign4(request, keys)
actual := actualSigned.Header.Get("X-Amz-Security-Token")
assert := assertions.New(t)
assert.So(actual, should.NotBeBlank)
assert.So(actual, should.Equal, testCredV4WithSTS.SecurityToken)
}
func TestVersion4SigningTasks(t *testing.T) {
// http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
Convey("Given a bogus request and credentials from AWS documentation with an additional meta tag", t, func() {
request := test_unsignedRequestV4(true, true)
meta := new(metadata)
// Given a bogus request and credentials from AWS documentation with an additional meta tag
request := test_unsignedRequestV4(true, true)
meta := new(metadata)
assert := assertions.New(t)
Convey("(Task 1) The canonical request should be built correctly", func() {
hashedCanonReq := hashedCanonicalRequestV4(request, meta)
// (Task 1) The canonical request should be built correctly
hashedCanonReq := hashedCanonicalRequestV4(request, meta)
assert.So(hashedCanonReq, should.Equal, expectingV4["CanonicalHash"])
So(hashedCanonReq, ShouldEqual, expectingV4["CanonicalHash"])
})
// (Task 2) The string to sign should be built correctly
stringToSign := stringToSignV4(request, hashedCanonReq, meta)
assert.So(stringToSign, should.Equal, expectingV4["StringToSign"])
Convey("(Task 2) The string to sign should be built correctly", func() {
hashedCanonReq := hashedCanonicalRequestV4(request, meta)
stringToSign := stringToSignV4(request, hashedCanonReq, meta)
So(stringToSign, ShouldEqual, expectingV4["StringToSign"])
})
Convey("(Task 3) The version 4 signed signature should be correct", func() {
hashedCanonReq := hashedCanonicalRequestV4(request, meta)
stringToSign := stringToSignV4(request, hashedCanonReq, meta)
signature := signatureV4(test_signingKeyV4(), stringToSign)
So(signature, ShouldEqual, expectingV4["SignatureV4"])
})
})
// (Task 3) The version 4 signed signature should be correct
signature := signatureV4(test_signingKeyV4(), stringToSign)
assert.So(signature, should.Equal, expectingV4["SignatureV4"])
}
func TestSignature4Helpers(t *testing.T) {
// The signing key should be properly generated
expected := []byte{152, 241, 216, 137, 254, 196, 244, 66, 26, 220, 82, 43, 171, 12, 225, 248, 46, 105, 41, 194, 98, 237, 21, 229, 169, 76, 144, 239, 209, 227, 176, 231}
actual := test_signingKeyV4()
keys := *testCredV4
assertions.New(t).So(actual, should.Resemble, expected)
}
func TestSignature4Helpers_1(t *testing.T) {
// Authorization headers should be built properly
meta := &metadata{
algorithm: "AWS4-HMAC-SHA256",
credentialScope: "20110909/us-east-1/iam/aws4_request",
signedHeaders: "content-type;host;x-amz-date",
}
expected := expectingV4["AuthHeader"] + expectingV4["SignatureV4"]
actual := buildAuthHeaderV4(expectingV4["SignatureV4"], meta, *testCredV4)
Convey("The signing key should be properly generated", t, func() {
expected := []byte{152, 241, 216, 137, 254, 196, 244, 66, 26, 220, 82, 43, 171, 12, 225, 248, 46, 105, 41, 194, 98, 237, 21, 229, 169, 76, 144, 239, 209, 227, 176, 231}
actual := test_signingKeyV4()
assertions.New(t).So(actual, should.Equal, expected)
}
func TestSignature4Helpers_2(t *testing.T) {
// Timestamps should be in the correct format, in UTC time
actual := timestampV4()
So(actual, ShouldResemble, expected)
})
assert := assertions.New(t)
assert.So(len(actual), should.Equal, 16)
assert.So(actual, should.NotContainSubstring, ":")
assert.So(actual, should.NotContainSubstring, "-")
assert.So(actual, should.NotContainSubstring, " ")
assert.So(actual, should.EndWith, "Z")
assert.So(actual, should.ContainSubstring, "T")
}
func TestSignature4Helpers_3(t *testing.T) {
// Given an Version 4 AWS-formatted timestamp
ts := "20110909T233600Z"
Convey("Authorization headers should be built properly", t, func() {
meta := &metadata{
algorithm: "AWS4-HMAC-SHA256",
credentialScope: "20110909/us-east-1/iam/aws4_request",
signedHeaders: "content-type;host;x-amz-date",
}
expected := expectingV4["AuthHeader"] + expectingV4["SignatureV4"]
actual := buildAuthHeaderV4(expectingV4["SignatureV4"], meta, keys)
// The date string should be extracted properly
assertions.New(t).So(tsDateV4(ts), should.Equal, "20110909")
}
func TestSignature4Helpers_4(t *testing.T) {
// Given any request with a body
request := test_plainRequestV4(false)
So(actual, ShouldEqual, expected)
})
// Its body should be read and replaced without differences
expected := []byte(requestValuesV4.Encode())
assert := assertions.New(t)
Convey("Timestamps should be in the correct format, in UTC time", t, func() {
actual := timestampV4()
actual1 := readAndReplaceBody(request)
assert.So(actual1, should.Resemble, expected)
So(len(actual), ShouldEqual, 16)
So(actual, ShouldNotContainSubstring, ":")
So(actual, ShouldNotContainSubstring, "-")
So(actual, ShouldNotContainSubstring, " ")
So(actual, ShouldEndWith, "Z")
So(actual, ShouldContainSubstring, "T")
})
Convey("Given an Version 4 AWS-formatted timestamp", t, func() {
ts := "20110909T233600Z"
Convey("The date string should be extracted properly", func() {
So(tsDateV4(ts), ShouldEqual, "20110909")
})
})
Convey("Given any request with a body", t, func() {
request := test_plainRequestV4(false)
Convey("Its body should be read and replaced without differences", func() {
expected := []byte(requestValuesV4.Encode())
actual1 := readAndReplaceBody(request)
So(actual1, ShouldResemble, expected)
actual2 := readAndReplaceBody(request)
So(actual2, ShouldResemble, expected)
})
})
actual2 := readAndReplaceBody(request)
assert.So(actual2, should.Resemble, expected)
}
func test_plainRequestV4(trailingSlash bool) *http.Request {
url := "http://iam.amazonaws.com"
address := "http://iam.amazonaws.com"
body := strings.NewReader(requestValuesV4.Encode())
if trailingSlash {
url += "/"
address += "/"
}
request, err := http.NewRequest("POST", url, body)
request, err := http.NewRequest("POST", address, body)
if err != nil {
panic(err)
@@ -191,6 +173,11 @@ func test_signingKeyV4() []byte {
return signingKeyV4(testCredV4.SecretAccessKey, "20110909", "us-east-1", "iam")
}
func dumpRequest(request *http.Request) string {
dump, _ := httputil.DumpRequestOut(request, true)
return string(dump)
}
var (
testCredV4 = &Credentials{
AccessKeyID: "AKIDEXAMPLE",