mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
Moving to glide
This commit is contained in:
parent
84d2482ddb
commit
38ee83e45b
1099 changed files with 277713 additions and 4019 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -69,6 +69,8 @@ web/sass-files/sass/.sass-cache/
|
|||
data/*
|
||||
api/data/*
|
||||
|
||||
enterprise
|
||||
|
||||
.agignore
|
||||
.ctags
|
||||
tags
|
||||
|
|
|
|||
221
Godeps/Godeps.json
generated
221
Godeps/Godeps.json
generated
|
|
@ -1,221 +0,0 @@
|
|||
{
|
||||
"ImportPath": "github.com/mattermost/platform",
|
||||
"GoVersion": "go1.6",
|
||||
"GodepVersion": "v65",
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/NYTimes/gziphandler",
|
||||
"Rev": "63027b26b87e2ae2ce3810393d4b81021cfd3a35"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/log4go",
|
||||
"Rev": "e5dc62318d9bd58682f1dceb53a4b24e8253682f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/braintree/manners",
|
||||
"Comment": "0.4.0-15-g82a8879",
|
||||
"Rev": "82a8879fc5fd0381fa8b2d8033b19bf255252088"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudfoundry/jibber_jabber",
|
||||
"Rev": "bcc4c8345a21301bf47c032ff42dd1aae2fe3027"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/dgryski/dgoogauth",
|
||||
"Rev": "67642ac6f9144f6610279e37e7be9af13f1cd668"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/disintegration/imaging",
|
||||
"Rev": "d8bbae1de109b518dabc98c6c1633eb358c148a4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/garyburd/redigo/internal",
|
||||
"Rev": "8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/garyburd/redigo/redis",
|
||||
"Rev": "8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-gorp/gorp",
|
||||
"Comment": "v1.7-184-g6a3c8a8",
|
||||
"Rev": "6a3c8a87d0457cf700e57046c41e19b7cf3c44fa"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-ldap/ldap",
|
||||
"Comment": "v2.3.0",
|
||||
"Rev": "0e7db8eb77695b5a952f0e5d78df9ab160050c73"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
"Comment": "v1.2-194-g7ebe0a5",
|
||||
"Rev": "7ebe0a500653eeb1859664bed5e48dec1e164e73"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/goamz/goamz/aws",
|
||||
"Rev": "02d5144a587b982e33b95f484a34164ce6923c99"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/goamz/goamz/s3",
|
||||
"Rev": "02d5144a587b982e33b95f484a34164ce6923c99"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/freetype",
|
||||
"Comment": "release-129-gc67e4d9",
|
||||
"Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/freetype/raster",
|
||||
"Comment": "release-129-gc67e4d9",
|
||||
"Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/freetype/truetype",
|
||||
"Comment": "release-129-gc67e4d9",
|
||||
"Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/groupcache/lru",
|
||||
"Rev": "4eab30f13db9d8b25c752e99d1583628ac2fa422"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/context",
|
||||
"Comment": "v1.1-2-ga8d44e7",
|
||||
"Rev": "a8d44e7d8e4d532b6a27a02dd82abb31cc1b01bd"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/handlers",
|
||||
"Comment": "v1.1-6-g66e6c6f",
|
||||
"Rev": "66e6c6f01d8da976ee113437745ca029c2b585a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/mux",
|
||||
"Comment": "v1.1-7-g9c19ed5",
|
||||
"Rev": "9c19ed558d5df4da88e2ade9c8940d742aef0e7e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/websocket",
|
||||
"Rev": "1f512fc3f05332ba7117626cdfb4e07474e58e60"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/lib/pq",
|
||||
"Comment": "go1.0-cutoff-86-gdd3290b",
|
||||
"Rev": "dd3290b2f71a8b30bee8e4e75a337a825263d26f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/lib/pq/oid",
|
||||
"Comment": "go1.0-cutoff-86-gdd3290b",
|
||||
"Rev": "dd3290b2f71a8b30bee8e4e75a337a825263d26f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattermost/rsc/gf256",
|
||||
"Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattermost/rsc/qr",
|
||||
"Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattermost/rsc/qr/coding",
|
||||
"Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mssola/user_agent",
|
||||
"Comment": "v0.4.1-14-g8e786bc",
|
||||
"Rev": "8e786bcb38b846e5eb8eb5f036d9144fc7b0a1f8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nicksnyder/go-i18n/i18n",
|
||||
"Comment": "v1.4.0",
|
||||
"Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nicksnyder/go-i18n/i18n/bundle",
|
||||
"Comment": "v1.4.0",
|
||||
"Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nicksnyder/go-i18n/i18n/language",
|
||||
"Comment": "v1.4.0",
|
||||
"Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nicksnyder/go-i18n/i18n/translation",
|
||||
"Comment": "v1.4.0",
|
||||
"Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Comment": "v1.0-11-gc55201b",
|
||||
"Rev": "c55201b036063326c5b1b89ccfe45a184973d073"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rwcarlsen/goexif/exif",
|
||||
"Rev": "709fab3d192d7c62f86043caff1e7e3fb0f42bd8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rwcarlsen/goexif/tiff",
|
||||
"Rev": "709fab3d192d7c62f86043caff1e7e3fb0f42bd8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vaughan0/go-ini",
|
||||
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||
"Rev": "91ab96ae987aef3e74ab78b3aaf026109d206148"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||
"Rev": "91ab96ae987aef3e74ab78b3aaf026109d206148"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/bmp",
|
||||
"Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/font",
|
||||
"Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/math/fixed",
|
||||
"Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/tiff",
|
||||
"Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/tiff/lzw",
|
||||
"Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "b776ec39b3e54652e09028aaaaac9757f4f8211a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/asn1-ber.v1",
|
||||
"Comment": "v1.1",
|
||||
"Rev": "4e86f4367175e39f69d9358a5f17b4dda270378d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fsnotify.v1",
|
||||
"Comment": "v1.3.0",
|
||||
"Rev": "30411dbcefb7a1da7e84f75530ad3abe4011b4f8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/throttled/throttled.v1",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "74e328a1af88a9b54f9eca1397d74ad98572a6df"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/throttled/throttled.v1/store",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "74e328a1af88a9b54f9eca1397d74ad98572a6df"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/yaml.v2",
|
||||
"Rev": "a83829b6f1293c91addabc89d0571c246397bbf4"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
Godeps/Readme
generated
5
Godeps/Readme
generated
|
|
@ -1,5 +0,0 @@
|
|||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
31
Makefile
31
Makefile
|
|
@ -1,7 +1,7 @@
|
|||
.PHONY: build package run stop run-client run-server stop-client stop-server restart-server restart-client start-docker clean-dist clean nuke check-style check-unit-tests test dist setup-mac prepare-enteprise run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows
|
||||
|
||||
# For golang 1.5.x compatibility (remove when we don't want to support it anymore)
|
||||
GO15VENDOREXPERIMENT=1
|
||||
export GO15VENDOREXPERIMENT=1
|
||||
|
||||
# Build Flags
|
||||
BUILD_NUMBER ?= $(BUILD_NUMBER:)
|
||||
|
|
@ -30,9 +30,9 @@ endif
|
|||
BUILD_WEBAPP_DIR = ./webapp
|
||||
|
||||
# Golang Flags
|
||||
GOPATH ?= $(GOPATH:)
|
||||
GOPATH ?= $(GOPATH:):./vendor
|
||||
GOFLAGS ?= $(GOFLAGS:)
|
||||
GO=$(GOPATH)/bin/godep go
|
||||
GO=go
|
||||
GO_LINKER_FLAGS ?= -ldflags \
|
||||
"-X github.com/mattermost/platform/model.BuildNumber=$(BUILD_NUMBER)\
|
||||
-X 'github.com/mattermost/platform/model.BuildDate=$(BUILD_DATE)'\
|
||||
|
|
@ -143,18 +143,20 @@ check-style:
|
|||
exit 1; \
|
||||
fi
|
||||
|
||||
test: start-docker
|
||||
test: prepare-enteprise start-docker
|
||||
@echo Running tests
|
||||
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
|
||||
#$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
|
||||
#$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
|
||||
#$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1
|
||||
#$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
|
||||
#$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
|
||||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||
@echo Running Enterprise tests
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/ldap || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/compliance || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -c ./enterprise/ldap && ./ldap.test -test.v -test.timeout=120s || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -c ./enterprise/compliance && ./compliance.test -test.v -test.timeout=120s || exit 1
|
||||
rm -r ldap.test
|
||||
rm -r compliance.test
|
||||
endif
|
||||
|
||||
setup-run-client-tests:
|
||||
|
|
@ -173,7 +175,7 @@ test-client: setup-run-client-tests run-server run-client-tests stop-server clea
|
|||
|
||||
.prebuild:
|
||||
@echo Preparation for running go code
|
||||
go get $(GOFLAGS) github.com/tools/godep
|
||||
go get $(GOFLAGS) github.com/Masterminds/glide
|
||||
|
||||
touch $@
|
||||
|
||||
|
|
@ -181,6 +183,8 @@ prepare-enterprise:
|
|||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||
@echo Enterprise build selected, preparing
|
||||
cp $(BUILD_ENTERPRISE_DIR)/imports.go .
|
||||
rm -f enterprise
|
||||
ln -s $(BUILD_ENTERPRISE_DIR) enterprise
|
||||
endif
|
||||
|
||||
build-linux: .prebuild prepare-enterprise
|
||||
|
|
@ -318,10 +322,9 @@ clean: stop-docker
|
|||
rm -rf api/data
|
||||
rm -rf logs
|
||||
|
||||
rm -rf Godeps/_workspace/pkg/
|
||||
|
||||
rm -f mattermost.log
|
||||
rm -f .prepare-go
|
||||
rm -f enterprise
|
||||
|
||||
nuke: clean clean-docker
|
||||
@echo BOOM
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@ type TestHelper struct {
|
|||
SystemAdminChannel *model.Channel
|
||||
}
|
||||
|
||||
func SetupEnterprise(platformDir string) *TestHelper {
|
||||
func SetupEnterprise() *TestHelper {
|
||||
if Srv == nil {
|
||||
utils.LoadConfig(platformDir + "/config/config.json")
|
||||
utils.InitTranslationsWithDir(platformDir + "/i18n")
|
||||
utils.LoadConfig("config.json")
|
||||
utils.InitTranslations()
|
||||
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
|
||||
utils.DisableDebugLogForTest()
|
||||
utils.License.Features.SetDefaults()
|
||||
NewServer()
|
||||
StartServer()
|
||||
utils.InitHTMLWithDir(platformDir + "/templates")
|
||||
utils.InitHTML()
|
||||
InitApi()
|
||||
utils.EnableDebugLogForTest()
|
||||
Srv.Store.MarkSystemRanUnitTests()
|
||||
|
|
|
|||
104
glide.lock
generated
Normal file
104
glide.lock
generated
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
hash: aa2fadc7f997a93e78d46d009d5695fb079697453d83e6a6dd7481d46ce73b7e
|
||||
updated: 2016-05-12T19:14:13.836695608-04:00
|
||||
imports:
|
||||
- name: github.com/alecthomas/log4go
|
||||
version: e5dc62318d9bd58682f1dceb53a4b24e8253682f
|
||||
- name: github.com/braintree/manners
|
||||
version: 82a8879fc5fd0381fa8b2d8033b19bf255252088
|
||||
- name: github.com/cloudfoundry/jibber_jabber
|
||||
version: bcc4c8345a21301bf47c032ff42dd1aae2fe3027
|
||||
- name: github.com/dgryski/dgoogauth
|
||||
version: 67642ac6f9144f6610279e37e7be9af13f1cd668
|
||||
- name: github.com/disintegration/imaging
|
||||
version: d8bbae1de109b518dabc98c6c1633eb358c148a4
|
||||
- name: github.com/garyburd/redigo
|
||||
version: 8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13
|
||||
subpackages:
|
||||
- redis
|
||||
- internal
|
||||
- name: github.com/go-gorp/gorp
|
||||
version: 6a3c8a87d0457cf700e57046c41e19b7cf3c44fa
|
||||
- name: github.com/go-ldap/ldap
|
||||
version: 0e7db8eb77695b5a952f0e5d78df9ab160050c73
|
||||
- name: github.com/go-sql-driver/mysql
|
||||
version: 7ebe0a500653eeb1859664bed5e48dec1e164e73
|
||||
- name: github.com/goamz/goamz
|
||||
version: 02d5144a587b982e33b95f484a34164ce6923c99
|
||||
subpackages:
|
||||
- aws
|
||||
- s3
|
||||
- name: github.com/golang/freetype
|
||||
version: c67e4d98d212356ec0d9436a1edcbb6eb799f847
|
||||
subpackages:
|
||||
- raster
|
||||
- truetype
|
||||
- name: github.com/golang/groupcache
|
||||
version: 4eab30f13db9d8b25c752e99d1583628ac2fa422
|
||||
subpackages:
|
||||
- lru
|
||||
- name: github.com/gorilla/context
|
||||
version: a8d44e7d8e4d532b6a27a02dd82abb31cc1b01bd
|
||||
- name: github.com/gorilla/handlers
|
||||
version: 66e6c6f01d8da976ee113437745ca029c2b585a6
|
||||
- name: github.com/gorilla/mux
|
||||
version: 9c19ed558d5df4da88e2ade9c8940d742aef0e7e
|
||||
- name: github.com/gorilla/websocket
|
||||
version: 1f512fc3f05332ba7117626cdfb4e07474e58e60
|
||||
- name: github.com/lib/pq
|
||||
version: ee1442bda7bd1b6a84e913bdb421cb1874ec629d
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/mattermost/rsc
|
||||
version: bbaefb05eaa0389ea712340066837c8ce4d287f9
|
||||
subpackages:
|
||||
- qr
|
||||
- qr/coding
|
||||
- gf256
|
||||
- name: github.com/mssola/user_agent
|
||||
version: 8e786bcb38b846e5eb8eb5f036d9144fc7b0a1f8
|
||||
- name: github.com/nicksnyder/go-i18n
|
||||
version: 37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3
|
||||
subpackages:
|
||||
- i18n
|
||||
- i18n/bundle
|
||||
- i18n/language
|
||||
- i18n/translation
|
||||
- name: github.com/NYTimes/gziphandler
|
||||
version: 63027b26b87e2ae2ce3810393d4b81021cfd3a35
|
||||
- name: github.com/pborman/uuid
|
||||
version: c55201b036063326c5b1b89ccfe45a184973d073
|
||||
- name: github.com/rwcarlsen/goexif
|
||||
version: 709fab3d192d7c62f86043caff1e7e3fb0f42bd8
|
||||
subpackages:
|
||||
- exif
|
||||
- tiff
|
||||
- name: github.com/vaughan0/go-ini
|
||||
version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
|
||||
- name: golang.org/x/crypto
|
||||
version: 1e61df8d9ea476e2e1504cd9a32b40280c7c6c7e
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- blowfish
|
||||
- name: golang.org/x/image
|
||||
version: f551d3a6b7fc11df315ad9e18b404280680f8bec
|
||||
subpackages:
|
||||
- bmp
|
||||
- tiff
|
||||
- font
|
||||
- math/fixed
|
||||
- tiff/lzw
|
||||
- name: golang.org/x/sys
|
||||
version: e82cb4d7dffc35bcec7bc8bf9e402377e0ecf3f4
|
||||
subpackages:
|
||||
- unix
|
||||
- name: gopkg.in/asn1-ber.v1
|
||||
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
|
||||
- name: gopkg.in/fsnotify.v1
|
||||
version: 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
|
||||
- name: gopkg.in/throttled/throttled.v1
|
||||
version: 74e328a1af88a9b54f9eca1397d74ad98572a6df
|
||||
subpackages:
|
||||
- store
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: a83829b6f1293c91addabc89d0571c246397bbf4
|
||||
devImports: []
|
||||
41
glide.yaml
Normal file
41
glide.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package: github.com/mattermost/platform
|
||||
import:
|
||||
- package: github.com/NYTimes/gziphandler
|
||||
- package: github.com/alecthomas/log4go
|
||||
- package: github.com/braintree/manners
|
||||
- package: github.com/cloudfoundry/jibber_jabber
|
||||
- package: github.com/dgryski/dgoogauth
|
||||
- package: github.com/disintegration/imaging
|
||||
- package: github.com/go-gorp/gorp
|
||||
- package: github.com/go-ldap/ldap
|
||||
- package: github.com/go-sql-driver/mysql
|
||||
- package: github.com/goamz/goamz
|
||||
subpackages:
|
||||
- aws
|
||||
- s3
|
||||
- package: github.com/golang/freetype
|
||||
- package: github.com/gorilla/handlers
|
||||
- package: github.com/gorilla/mux
|
||||
- package: github.com/gorilla/websocket
|
||||
- package: github.com/lib/pq
|
||||
- package: github.com/mattermost/rsc
|
||||
subpackages:
|
||||
- qr
|
||||
- package: github.com/mssola/user_agent
|
||||
- package: github.com/nicksnyder/go-i18n
|
||||
subpackages:
|
||||
- i18n
|
||||
- package: github.com/pborman/uuid
|
||||
- package: github.com/rwcarlsen/goexif
|
||||
subpackages:
|
||||
- exif
|
||||
- package: golang.org/x/crypto
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- package: golang.org/x/image
|
||||
subpackages:
|
||||
- bmp
|
||||
- package: gopkg.in/fsnotify.v1
|
||||
- package: gopkg.in/throttled/throttled.v1
|
||||
subpackages:
|
||||
- store
|
||||
134
vendor/github.com/NYTimes/gziphandler/gzip_test.go
generated
vendored
Normal file
134
vendor/github.com/NYTimes/gziphandler/gzip_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
package gziphandler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseEncodings(t *testing.T) {
|
||||
|
||||
examples := map[string]codings{
|
||||
|
||||
// Examples from RFC 2616
|
||||
"compress, gzip": codings{"compress": 1.0, "gzip": 1.0},
|
||||
"": codings{},
|
||||
"*": codings{"*": 1.0},
|
||||
"compress;q=0.5, gzip;q=1.0": codings{"compress": 0.5, "gzip": 1.0},
|
||||
"gzip;q=1.0, identity; q=0.5, *;q=0": codings{"gzip": 1.0, "identity": 0.5, "*": 0.0},
|
||||
|
||||
// More random stuff
|
||||
"AAA;q=1": codings{"aaa": 1.0},
|
||||
"BBB ; q = 2": codings{"bbb": 1.0},
|
||||
}
|
||||
|
||||
for eg, exp := range examples {
|
||||
act, _ := parseEncodings(eg)
|
||||
assert.Equal(t, exp, act)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGzipHandler(t *testing.T) {
|
||||
testBody := "aaabbbccc"
|
||||
|
||||
// This just exists to provide something for GzipHandler to wrap.
|
||||
handler := newTestHandler(testBody)
|
||||
|
||||
// requests without accept-encoding are passed along as-is
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/whatever", nil)
|
||||
res1 := httptest.NewRecorder()
|
||||
handler.ServeHTTP(res1, req1)
|
||||
|
||||
assert.Equal(t, 200, res1.Code)
|
||||
assert.Equal(t, "", res1.Header().Get("Content-Encoding"))
|
||||
assert.Equal(t, "Accept-Encoding", res1.Header().Get("Vary"))
|
||||
assert.Equal(t, testBody, res1.Body.String())
|
||||
|
||||
// but requests with accept-encoding:gzip are compressed if possible
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/whatever", nil)
|
||||
req2.Header.Set("Accept-Encoding", "gzip")
|
||||
res2 := httptest.NewRecorder()
|
||||
handler.ServeHTTP(res2, req2)
|
||||
|
||||
assert.Equal(t, 200, res2.Code)
|
||||
assert.Equal(t, "gzip", res2.Header().Get("Content-Encoding"))
|
||||
assert.Equal(t, "Accept-Encoding", res2.Header().Get("Vary"))
|
||||
assert.Equal(t, gzipStr(testBody), res2.Body.Bytes())
|
||||
|
||||
// content-type header is correctly set based on uncompressed body
|
||||
|
||||
req3, _ := http.NewRequest("GET", "/whatever", nil)
|
||||
req3.Header.Set("Accept-Encoding", "gzip")
|
||||
res3 := httptest.NewRecorder()
|
||||
handler.ServeHTTP(res3, req3)
|
||||
|
||||
assert.Equal(t, http.DetectContentType([]byte(testBody)), res3.Header().Get("Content-Type"))
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
func BenchmarkGzipHandler_S2k(b *testing.B) { benchmark(b, false, 2048) }
|
||||
func BenchmarkGzipHandler_S20k(b *testing.B) { benchmark(b, false, 20480) }
|
||||
func BenchmarkGzipHandler_S100k(b *testing.B) { benchmark(b, false, 102400) }
|
||||
func BenchmarkGzipHandler_P2k(b *testing.B) { benchmark(b, true, 2048) }
|
||||
func BenchmarkGzipHandler_P20k(b *testing.B) { benchmark(b, true, 20480) }
|
||||
func BenchmarkGzipHandler_P100k(b *testing.B) { benchmark(b, true, 102400) }
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
func gzipStr(s string) []byte {
|
||||
var b bytes.Buffer
|
||||
w := gzip.NewWriter(&b)
|
||||
io.WriteString(w, s)
|
||||
w.Close()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func benchmark(b *testing.B, parallel bool, size int) {
|
||||
bin, err := ioutil.ReadFile("testdata/benchmark.json")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", "/whatever", nil)
|
||||
req.Header.Set("Accept-Encoding", "gzip")
|
||||
handler := newTestHandler(string(bin[:size]))
|
||||
|
||||
if parallel {
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
runBenchmark(b, req, handler)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
runBenchmark(b, req, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runBenchmark(b *testing.B, req *http.Request, handler http.Handler) {
|
||||
res := httptest.NewRecorder()
|
||||
handler.ServeHTTP(res, req)
|
||||
if code := res.Code; code != 200 {
|
||||
b.Fatalf("Expected 200 but got %d", code)
|
||||
} else if blen := res.Body.Len(); blen < 500 {
|
||||
b.Fatalf("Expected complete response body, but got %d bytes", blen)
|
||||
}
|
||||
}
|
||||
|
||||
func newTestHandler(body string) http.Handler {
|
||||
return GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
io.WriteString(w, body)
|
||||
}))
|
||||
}
|
||||
5456
vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json
generated
vendored
Normal file
5456
vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
14
vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
generated
vendored
Normal file
14
vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
import l4g "code.google.com/p/log4go"
|
||||
|
||||
func main() {
|
||||
log := l4g.NewLogger()
|
||||
defer log.Close()
|
||||
log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
|
||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
||||
}
|
||||
57
vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
generated
vendored
Normal file
57
vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
import l4g "code.google.com/p/log4go"
|
||||
|
||||
const (
|
||||
filename = "flw.log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Get a new logger instance
|
||||
log := l4g.NewLogger()
|
||||
|
||||
// Create a default logger that is logging messages of FINE or higher
|
||||
log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false))
|
||||
log.Close()
|
||||
|
||||
/* Can also specify manually via the following: (these are the defaults) */
|
||||
flw := l4g.NewFileLogWriter(filename, false)
|
||||
flw.SetFormat("[%D %T] [%L] (%S) %M")
|
||||
flw.SetRotate(false)
|
||||
flw.SetRotateSize(0)
|
||||
flw.SetRotateLines(0)
|
||||
flw.SetRotateDaily(false)
|
||||
log.AddFilter("file", l4g.FINE, flw)
|
||||
|
||||
// Log some experimental messages
|
||||
log.Finest("Everything is created now (notice that I will not be printing to the file)")
|
||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
||||
log.Critical("Time to close out!")
|
||||
|
||||
// Close the log
|
||||
log.Close()
|
||||
|
||||
// Print what was logged to the file (yes, I know I'm skipping error checking)
|
||||
fd, _ := os.Open(filename)
|
||||
in := bufio.NewReader(fd)
|
||||
fmt.Print("Messages logged to file were: (line numbers not included)\n")
|
||||
for lineno := 1; ; lineno++ {
|
||||
line, err := in.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
fmt.Printf("%3d:\t%s", lineno, line)
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
// Remove the file so it's not lying around
|
||||
os.Remove(filename)
|
||||
}
|
||||
42
vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
generated
vendored
Normal file
42
vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
port = flag.String("p", "12124", "Port number to listen on")
|
||||
)
|
||||
|
||||
func e(err error) {
|
||||
if err != nil {
|
||||
fmt.Printf("Erroring out: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Bind to the port
|
||||
bind, err := net.ResolveUDPAddr("0.0.0.0:" + *port)
|
||||
e(err)
|
||||
|
||||
// Create listener
|
||||
listener, err := net.ListenUDP("udp", bind)
|
||||
e(err)
|
||||
|
||||
fmt.Printf("Listening to port %s...\n", *port)
|
||||
for {
|
||||
// read into a new buffer
|
||||
buffer := make([]byte, 1024)
|
||||
_, _, err := listener.ReadFrom(buffer)
|
||||
e(err)
|
||||
|
||||
// log to standard output
|
||||
fmt.Println(string(buffer))
|
||||
}
|
||||
}
|
||||
18
vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
generated
vendored
Normal file
18
vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
import l4g "code.google.com/p/log4go"
|
||||
|
||||
func main() {
|
||||
log := l4g.NewLogger()
|
||||
log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
|
||||
|
||||
// Run `nc -u -l -p 12124` or similar before you run this to see the following message
|
||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
||||
|
||||
// This makes sure the output stream buffer is written
|
||||
log.Close()
|
||||
}
|
||||
13
vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
generated
vendored
Normal file
13
vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import l4g "code.google.com/p/log4go"
|
||||
|
||||
func main() {
|
||||
// Load the configuration (isn't this easy?)
|
||||
l4g.LoadConfiguration("example.xml")
|
||||
|
||||
// And now we're ready!
|
||||
l4g.Finest("This will only go to those of you really cool UDP kids! If you change enabled=true.")
|
||||
l4g.Debug("Oh no! %d + %d = %d!", 2, 2, 2+2)
|
||||
l4g.Info("About that time, eh chaps?")
|
||||
}
|
||||
47
vendor/github.com/alecthomas/log4go/examples/example.xml
generated
vendored
Normal file
47
vendor/github.com/alecthomas/log4go/examples/example.xml
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<logging>
|
||||
<filter enabled="true">
|
||||
<tag>stdout</tag>
|
||||
<type>console</type>
|
||||
<!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<filter enabled="true">
|
||||
<tag>file</tag>
|
||||
<type>file</type>
|
||||
<level>FINEST</level>
|
||||
<property name="filename">test.log</property>
|
||||
<!--
|
||||
%T - Time (15:04:05 MST)
|
||||
%t - Time (15:04)
|
||||
%D - Date (2006/01/02)
|
||||
%d - Date (01/02/06)
|
||||
%L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
|
||||
%S - Source
|
||||
%M - Message
|
||||
It ignores unknown format strings (and removes them)
|
||||
Recommended: "[%D %T] [%L] (%S) %M"
|
||||
-->
|
||||
<property name="format">[%D %T] [%L] (%S) %M</property>
|
||||
<property name="rotate">false</property> <!-- true enables log rotation, otherwise append -->
|
||||
<property name="maxsize">0M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
|
||||
<property name="maxlines">0K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
|
||||
<property name="daily">true</property> <!-- Automatically rotates when a log message is written after midnight -->
|
||||
</filter>
|
||||
<filter enabled="true">
|
||||
<tag>xmllog</tag>
|
||||
<type>xml</type>
|
||||
<level>TRACE</level>
|
||||
<property name="filename">trace.xml</property>
|
||||
<property name="rotate">true</property> <!-- true enables log rotation, otherwise append -->
|
||||
<property name="maxsize">100M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
|
||||
<property name="maxrecords">6K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
|
||||
<property name="daily">false</property> <!-- Automatically rotates when a log message is written after midnight -->
|
||||
</filter>
|
||||
<filter enabled="false"><!-- enabled=false means this logger won't actually be created -->
|
||||
<tag>donotopen</tag>
|
||||
<type>socket</type>
|
||||
<level>FINEST</level>
|
||||
<property name="endpoint">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->
|
||||
<property name="protocol">udp</property> <!-- tcp or udp -->
|
||||
</filter>
|
||||
</logging>
|
||||
534
vendor/github.com/alecthomas/log4go/log4go_test.go
generated
vendored
Normal file
534
vendor/github.com/alecthomas/log4go/log4go_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
|
||||
|
||||
package log4go
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const testLogFile = "_logtest.log"
|
||||
|
||||
var now time.Time = time.Unix(0, 1234567890123456789).In(time.UTC)
|
||||
|
||||
func newLogRecord(lvl Level, src string, msg string) *LogRecord {
|
||||
return &LogRecord{
|
||||
Level: lvl,
|
||||
Source: src,
|
||||
Created: now,
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func TestELog(t *testing.T) {
|
||||
fmt.Printf("Testing %s\n", L4G_VERSION)
|
||||
lr := newLogRecord(CRITICAL, "source", "message")
|
||||
if lr.Level != CRITICAL {
|
||||
t.Errorf("Incorrect level: %d should be %d", lr.Level, CRITICAL)
|
||||
}
|
||||
if lr.Source != "source" {
|
||||
t.Errorf("Incorrect source: %s should be %s", lr.Source, "source")
|
||||
}
|
||||
if lr.Message != "message" {
|
||||
t.Errorf("Incorrect message: %s should be %s", lr.Source, "message")
|
||||
}
|
||||
}
|
||||
|
||||
var formatTests = []struct {
|
||||
Test string
|
||||
Record *LogRecord
|
||||
Formats map[string]string
|
||||
}{
|
||||
{
|
||||
Test: "Standard formats",
|
||||
Record: &LogRecord{
|
||||
Level: ERROR,
|
||||
Source: "source",
|
||||
Message: "message",
|
||||
Created: now,
|
||||
},
|
||||
Formats: map[string]string{
|
||||
// TODO(kevlar): How can I do this so it'll work outside of PST?
|
||||
FORMAT_DEFAULT: "[2009/02/13 23:31:30 UTC] [EROR] (source) message\n",
|
||||
FORMAT_SHORT: "[23:31 13/02/09] [EROR] message\n",
|
||||
FORMAT_ABBREV: "[EROR] message\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestFormatLogRecord(t *testing.T) {
|
||||
for _, test := range formatTests {
|
||||
name := test.Test
|
||||
for fmt, want := range test.Formats {
|
||||
if got := FormatLogRecord(fmt, test.Record); got != want {
|
||||
t.Errorf("%s - %s:", name, fmt)
|
||||
t.Errorf(" got %q", got)
|
||||
t.Errorf(" want %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var logRecordWriteTests = []struct {
|
||||
Test string
|
||||
Record *LogRecord
|
||||
Console string
|
||||
}{
|
||||
{
|
||||
Test: "Normal message",
|
||||
Record: &LogRecord{
|
||||
Level: CRITICAL,
|
||||
Source: "source",
|
||||
Message: "message",
|
||||
Created: now,
|
||||
},
|
||||
Console: "[23:31:30 UTC 2009/02/13] [CRIT] message\n",
|
||||
},
|
||||
}
|
||||
|
||||
func TestConsoleLogWriter(t *testing.T) {
|
||||
console := make(ConsoleLogWriter)
|
||||
|
||||
r, w := io.Pipe()
|
||||
go console.run(w)
|
||||
defer console.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
for _, test := range logRecordWriteTests {
|
||||
name := test.Test
|
||||
|
||||
console.LogWrite(test.Record)
|
||||
n, _ := r.Read(buf)
|
||||
|
||||
if got, want := string(buf[:n]), test.Console; got != want {
|
||||
t.Errorf("%s: got %q", name, got)
|
||||
t.Errorf("%s: want %q", name, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileLogWriter(t *testing.T) {
|
||||
defer func(buflen int) {
|
||||
LogBufferLength = buflen
|
||||
}(LogBufferLength)
|
||||
LogBufferLength = 0
|
||||
|
||||
w := NewFileLogWriter(testLogFile, false)
|
||||
if w == nil {
|
||||
t.Fatalf("Invalid return: w should not be nil")
|
||||
}
|
||||
defer os.Remove(testLogFile)
|
||||
|
||||
w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
|
||||
w.Close()
|
||||
runtime.Gosched()
|
||||
|
||||
if contents, err := ioutil.ReadFile(testLogFile); err != nil {
|
||||
t.Errorf("read(%q): %s", testLogFile, err)
|
||||
} else if len(contents) != 50 {
|
||||
t.Errorf("malformed filelog: %q (%d bytes)", string(contents), len(contents))
|
||||
}
|
||||
}
|
||||
|
||||
func TestXMLLogWriter(t *testing.T) {
|
||||
defer func(buflen int) {
|
||||
LogBufferLength = buflen
|
||||
}(LogBufferLength)
|
||||
LogBufferLength = 0
|
||||
|
||||
w := NewXMLLogWriter(testLogFile, false)
|
||||
if w == nil {
|
||||
t.Fatalf("Invalid return: w should not be nil")
|
||||
}
|
||||
defer os.Remove(testLogFile)
|
||||
|
||||
w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
|
||||
w.Close()
|
||||
runtime.Gosched()
|
||||
|
||||
if contents, err := ioutil.ReadFile(testLogFile); err != nil {
|
||||
t.Errorf("read(%q): %s", testLogFile, err)
|
||||
} else if len(contents) != 185 {
|
||||
t.Errorf("malformed xmllog: %q (%d bytes)", string(contents), len(contents))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
sl := NewDefaultLogger(WARNING)
|
||||
if sl == nil {
|
||||
t.Fatalf("NewDefaultLogger should never return nil")
|
||||
}
|
||||
if lw, exist := sl["stdout"]; lw == nil || exist != true {
|
||||
t.Fatalf("NewDefaultLogger produced invalid logger (DNE or nil)")
|
||||
}
|
||||
if sl["stdout"].Level != WARNING {
|
||||
t.Fatalf("NewDefaultLogger produced invalid logger (incorrect level)")
|
||||
}
|
||||
if len(sl) != 1 {
|
||||
t.Fatalf("NewDefaultLogger produced invalid logger (incorrect map count)")
|
||||
}
|
||||
|
||||
//func (l *Logger) AddFilter(name string, level int, writer LogWriter) {}
|
||||
l := make(Logger)
|
||||
l.AddFilter("stdout", DEBUG, NewConsoleLogWriter())
|
||||
if lw, exist := l["stdout"]; lw == nil || exist != true {
|
||||
t.Fatalf("AddFilter produced invalid logger (DNE or nil)")
|
||||
}
|
||||
if l["stdout"].Level != DEBUG {
|
||||
t.Fatalf("AddFilter produced invalid logger (incorrect level)")
|
||||
}
|
||||
if len(l) != 1 {
|
||||
t.Fatalf("AddFilter produced invalid logger (incorrect map count)")
|
||||
}
|
||||
|
||||
//func (l *Logger) Warn(format string, args ...interface{}) error {}
|
||||
if err := l.Warn("%s %d %#v", "Warning:", 1, []int{}); err.Error() != "Warning: 1 []int{}" {
|
||||
t.Errorf("Warn returned invalid error: %s", err)
|
||||
}
|
||||
|
||||
//func (l *Logger) Error(format string, args ...interface{}) error {}
|
||||
if err := l.Error("%s %d %#v", "Error:", 10, []string{}); err.Error() != "Error: 10 []string{}" {
|
||||
t.Errorf("Error returned invalid error: %s", err)
|
||||
}
|
||||
|
||||
//func (l *Logger) Critical(format string, args ...interface{}) error {}
|
||||
if err := l.Critical("%s %d %#v", "Critical:", 100, []int64{}); err.Error() != "Critical: 100 []int64{}" {
|
||||
t.Errorf("Critical returned invalid error: %s", err)
|
||||
}
|
||||
|
||||
// Already tested or basically untestable
|
||||
//func (l *Logger) Log(level int, source, message string) {}
|
||||
//func (l *Logger) Logf(level int, format string, args ...interface{}) {}
|
||||
//func (l *Logger) intLogf(level int, format string, args ...interface{}) string {}
|
||||
//func (l *Logger) Finest(format string, args ...interface{}) {}
|
||||
//func (l *Logger) Fine(format string, args ...interface{}) {}
|
||||
//func (l *Logger) Debug(format string, args ...interface{}) {}
|
||||
//func (l *Logger) Trace(format string, args ...interface{}) {}
|
||||
//func (l *Logger) Info(format string, args ...interface{}) {}
|
||||
}
|
||||
|
||||
func TestLogOutput(t *testing.T) {
|
||||
const (
|
||||
expected = "fdf3e51e444da56b4cb400f30bc47424"
|
||||
)
|
||||
|
||||
// Unbuffered output
|
||||
defer func(buflen int) {
|
||||
LogBufferLength = buflen
|
||||
}(LogBufferLength)
|
||||
LogBufferLength = 0
|
||||
|
||||
l := make(Logger)
|
||||
|
||||
// Delete and open the output log without a timestamp (for a constant md5sum)
|
||||
l.AddFilter("file", FINEST, NewFileLogWriter(testLogFile, false).SetFormat("[%L] %M"))
|
||||
defer os.Remove(testLogFile)
|
||||
|
||||
// Send some log messages
|
||||
l.Log(CRITICAL, "testsrc1", fmt.Sprintf("This message is level %d", int(CRITICAL)))
|
||||
l.Logf(ERROR, "This message is level %v", ERROR)
|
||||
l.Logf(WARNING, "This message is level %s", WARNING)
|
||||
l.Logc(INFO, func() string { return "This message is level INFO" })
|
||||
l.Trace("This message is level %d", int(TRACE))
|
||||
l.Debug("This message is level %s", DEBUG)
|
||||
l.Fine(func() string { return fmt.Sprintf("This message is level %v", FINE) })
|
||||
l.Finest("This message is level %v", FINEST)
|
||||
l.Finest(FINEST, "is also this message's level")
|
||||
|
||||
l.Close()
|
||||
|
||||
contents, err := ioutil.ReadFile(testLogFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not read output log: %s", err)
|
||||
}
|
||||
|
||||
sum := md5.New()
|
||||
sum.Write(contents)
|
||||
if sumstr := hex.EncodeToString(sum.Sum(nil)); sumstr != expected {
|
||||
t.Errorf("--- Log Contents:\n%s---", string(contents))
|
||||
t.Fatalf("Checksum does not match: %s (expecting %s)", sumstr, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountMallocs(t *testing.T) {
|
||||
const N = 1
|
||||
var m runtime.MemStats
|
||||
getMallocs := func() uint64 {
|
||||
runtime.ReadMemStats(&m)
|
||||
return m.Mallocs
|
||||
}
|
||||
|
||||
// Console logger
|
||||
sl := NewDefaultLogger(INFO)
|
||||
mallocs := 0 - getMallocs()
|
||||
for i := 0; i < N; i++ {
|
||||
sl.Log(WARNING, "here", "This is a WARNING message")
|
||||
}
|
||||
mallocs += getMallocs()
|
||||
fmt.Printf("mallocs per sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
|
||||
|
||||
// Console logger formatted
|
||||
mallocs = 0 - getMallocs()
|
||||
for i := 0; i < N; i++ {
|
||||
sl.Logf(WARNING, "%s is a log message with level %d", "This", WARNING)
|
||||
}
|
||||
mallocs += getMallocs()
|
||||
fmt.Printf("mallocs per sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
|
||||
|
||||
// Console logger (not logged)
|
||||
sl = NewDefaultLogger(INFO)
|
||||
mallocs = 0 - getMallocs()
|
||||
for i := 0; i < N; i++ {
|
||||
sl.Log(DEBUG, "here", "This is a DEBUG log message")
|
||||
}
|
||||
mallocs += getMallocs()
|
||||
fmt.Printf("mallocs per unlogged sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
|
||||
|
||||
// Console logger formatted (not logged)
|
||||
mallocs = 0 - getMallocs()
|
||||
for i := 0; i < N; i++ {
|
||||
sl.Logf(DEBUG, "%s is a log message with level %d", "This", DEBUG)
|
||||
}
|
||||
mallocs += getMallocs()
|
||||
fmt.Printf("mallocs per unlogged sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
|
||||
}
|
||||
|
||||
func TestXMLConfig(t *testing.T) {
|
||||
const (
|
||||
configfile = "example.xml"
|
||||
)
|
||||
|
||||
fd, err := os.Create(configfile)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not open %s for writing: %s", configfile, err)
|
||||
}
|
||||
|
||||
fmt.Fprintln(fd, "<logging>")
|
||||
fmt.Fprintln(fd, " <filter enabled=\"true\">")
|
||||
fmt.Fprintln(fd, " <tag>stdout</tag>")
|
||||
fmt.Fprintln(fd, " <type>console</type>")
|
||||
fmt.Fprintln(fd, " <!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->")
|
||||
fmt.Fprintln(fd, " <level>DEBUG</level>")
|
||||
fmt.Fprintln(fd, " </filter>")
|
||||
fmt.Fprintln(fd, " <filter enabled=\"true\">")
|
||||
fmt.Fprintln(fd, " <tag>file</tag>")
|
||||
fmt.Fprintln(fd, " <type>file</type>")
|
||||
fmt.Fprintln(fd, " <level>FINEST</level>")
|
||||
fmt.Fprintln(fd, " <property name=\"filename\">test.log</property>")
|
||||
fmt.Fprintln(fd, " <!--")
|
||||
fmt.Fprintln(fd, " %T - Time (15:04:05 MST)")
|
||||
fmt.Fprintln(fd, " %t - Time (15:04)")
|
||||
fmt.Fprintln(fd, " %D - Date (2006/01/02)")
|
||||
fmt.Fprintln(fd, " %d - Date (01/02/06)")
|
||||
fmt.Fprintln(fd, " %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)")
|
||||
fmt.Fprintln(fd, " %S - Source")
|
||||
fmt.Fprintln(fd, " %M - Message")
|
||||
fmt.Fprintln(fd, " It ignores unknown format strings (and removes them)")
|
||||
fmt.Fprintln(fd, " Recommended: \"[%D %T] [%L] (%S) %M\"")
|
||||
fmt.Fprintln(fd, " -->")
|
||||
fmt.Fprintln(fd, " <property name=\"format\">[%D %T] [%L] (%S) %M</property>")
|
||||
fmt.Fprintln(fd, " <property name=\"rotate\">false</property> <!-- true enables log rotation, otherwise append -->")
|
||||
fmt.Fprintln(fd, " <property name=\"maxsize\">0M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
|
||||
fmt.Fprintln(fd, " <property name=\"maxlines\">0K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
|
||||
fmt.Fprintln(fd, " <property name=\"daily\">true</property> <!-- Automatically rotates when a log message is written after midnight -->")
|
||||
fmt.Fprintln(fd, " </filter>")
|
||||
fmt.Fprintln(fd, " <filter enabled=\"true\">")
|
||||
fmt.Fprintln(fd, " <tag>xmllog</tag>")
|
||||
fmt.Fprintln(fd, " <type>xml</type>")
|
||||
fmt.Fprintln(fd, " <level>TRACE</level>")
|
||||
fmt.Fprintln(fd, " <property name=\"filename\">trace.xml</property>")
|
||||
fmt.Fprintln(fd, " <property name=\"rotate\">true</property> <!-- true enables log rotation, otherwise append -->")
|
||||
fmt.Fprintln(fd, " <property name=\"maxsize\">100M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
|
||||
fmt.Fprintln(fd, " <property name=\"maxrecords\">6K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
|
||||
fmt.Fprintln(fd, " <property name=\"daily\">false</property> <!-- Automatically rotates when a log message is written after midnight -->")
|
||||
fmt.Fprintln(fd, " </filter>")
|
||||
fmt.Fprintln(fd, " <filter enabled=\"false\"><!-- enabled=false means this logger won't actually be created -->")
|
||||
fmt.Fprintln(fd, " <tag>donotopen</tag>")
|
||||
fmt.Fprintln(fd, " <type>socket</type>")
|
||||
fmt.Fprintln(fd, " <level>FINEST</level>")
|
||||
fmt.Fprintln(fd, " <property name=\"endpoint\">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->")
|
||||
fmt.Fprintln(fd, " <property name=\"protocol\">udp</property> <!-- tcp or udp -->")
|
||||
fmt.Fprintln(fd, " </filter>")
|
||||
fmt.Fprintln(fd, "</logging>")
|
||||
fd.Close()
|
||||
|
||||
log := make(Logger)
|
||||
log.LoadConfiguration(configfile)
|
||||
defer os.Remove("trace.xml")
|
||||
defer os.Remove("test.log")
|
||||
defer log.Close()
|
||||
|
||||
// Make sure we got all loggers
|
||||
if len(log) != 3 {
|
||||
t.Fatalf("XMLConfig: Expected 3 filters, found %d", len(log))
|
||||
}
|
||||
|
||||
// Make sure they're the right keys
|
||||
if _, ok := log["stdout"]; !ok {
|
||||
t.Errorf("XMLConfig: Expected stdout logger")
|
||||
}
|
||||
if _, ok := log["file"]; !ok {
|
||||
t.Fatalf("XMLConfig: Expected file logger")
|
||||
}
|
||||
if _, ok := log["xmllog"]; !ok {
|
||||
t.Fatalf("XMLConfig: Expected xmllog logger")
|
||||
}
|
||||
|
||||
// Make sure they're the right type
|
||||
if _, ok := log["stdout"].LogWriter.(ConsoleLogWriter); !ok {
|
||||
t.Fatalf("XMLConfig: Expected stdout to be ConsoleLogWriter, found %T", log["stdout"].LogWriter)
|
||||
}
|
||||
if _, ok := log["file"].LogWriter.(*FileLogWriter); !ok {
|
||||
t.Fatalf("XMLConfig: Expected file to be *FileLogWriter, found %T", log["file"].LogWriter)
|
||||
}
|
||||
if _, ok := log["xmllog"].LogWriter.(*FileLogWriter); !ok {
|
||||
t.Fatalf("XMLConfig: Expected xmllog to be *FileLogWriter, found %T", log["xmllog"].LogWriter)
|
||||
}
|
||||
|
||||
// Make sure levels are set
|
||||
if lvl := log["stdout"].Level; lvl != DEBUG {
|
||||
t.Errorf("XMLConfig: Expected stdout to be set to level %d, found %d", DEBUG, lvl)
|
||||
}
|
||||
if lvl := log["file"].Level; lvl != FINEST {
|
||||
t.Errorf("XMLConfig: Expected file to be set to level %d, found %d", FINEST, lvl)
|
||||
}
|
||||
if lvl := log["xmllog"].Level; lvl != TRACE {
|
||||
t.Errorf("XMLConfig: Expected xmllog to be set to level %d, found %d", TRACE, lvl)
|
||||
}
|
||||
|
||||
// Make sure the w is open and points to the right file
|
||||
if fname := log["file"].LogWriter.(*FileLogWriter).file.Name(); fname != "test.log" {
|
||||
t.Errorf("XMLConfig: Expected file to have opened %s, found %s", "test.log", fname)
|
||||
}
|
||||
|
||||
// Make sure the XLW is open and points to the right file
|
||||
if fname := log["xmllog"].LogWriter.(*FileLogWriter).file.Name(); fname != "trace.xml" {
|
||||
t.Errorf("XMLConfig: Expected xmllog to have opened %s, found %s", "trace.xml", fname)
|
||||
}
|
||||
|
||||
// Move XML log file
|
||||
os.Rename(configfile, "examples/"+configfile) // Keep this so that an example with the documentation is available
|
||||
}
|
||||
|
||||
func BenchmarkFormatLogRecord(b *testing.B) {
|
||||
const updateEvery = 1
|
||||
rec := &LogRecord{
|
||||
Level: CRITICAL,
|
||||
Created: now,
|
||||
Source: "source",
|
||||
Message: "message",
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
rec.Created = rec.Created.Add(1 * time.Second / updateEvery)
|
||||
if i%2 == 0 {
|
||||
FormatLogRecord(FORMAT_DEFAULT, rec)
|
||||
} else {
|
||||
FormatLogRecord(FORMAT_SHORT, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConsoleLog(b *testing.B) {
|
||||
/* This doesn't seem to work on OS X
|
||||
sink, err := os.Open(os.DevNull)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := syscall.Dup2(int(sink.Fd()), syscall.Stdout); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
|
||||
stdout = ioutil.Discard
|
||||
sl := NewDefaultLogger(INFO)
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Log(WARNING, "here", "This is a log message")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConsoleNotLogged(b *testing.B) {
|
||||
sl := NewDefaultLogger(INFO)
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Log(DEBUG, "here", "This is a log message")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConsoleUtilLog(b *testing.B) {
|
||||
sl := NewDefaultLogger(INFO)
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Info("%s is a log message", "This")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConsoleUtilNotLog(b *testing.B) {
|
||||
sl := NewDefaultLogger(INFO)
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Debug("%s is a log message", "This")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFileLog(b *testing.B) {
|
||||
sl := make(Logger)
|
||||
b.StopTimer()
|
||||
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Log(WARNING, "here", "This is a log message")
|
||||
}
|
||||
b.StopTimer()
|
||||
os.Remove("benchlog.log")
|
||||
}
|
||||
|
||||
func BenchmarkFileNotLogged(b *testing.B) {
|
||||
sl := make(Logger)
|
||||
b.StopTimer()
|
||||
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Log(DEBUG, "here", "This is a log message")
|
||||
}
|
||||
b.StopTimer()
|
||||
os.Remove("benchlog.log")
|
||||
}
|
||||
|
||||
func BenchmarkFileUtilLog(b *testing.B) {
|
||||
sl := make(Logger)
|
||||
b.StopTimer()
|
||||
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Info("%s is a log message", "This")
|
||||
}
|
||||
b.StopTimer()
|
||||
os.Remove("benchlog.log")
|
||||
}
|
||||
|
||||
func BenchmarkFileUtilNotLog(b *testing.B) {
|
||||
sl := make(Logger)
|
||||
b.StopTimer()
|
||||
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sl.Debug("%s is a log message", "This")
|
||||
}
|
||||
b.StopTimer()
|
||||
os.Remove("benchlog.log")
|
||||
}
|
||||
|
||||
// Benchmark results (darwin amd64 6g)
|
||||
//elog.BenchmarkConsoleLog 100000 22819 ns/op
|
||||
//elog.BenchmarkConsoleNotLogged 2000000 879 ns/op
|
||||
//elog.BenchmarkConsoleUtilLog 50000 34380 ns/op
|
||||
//elog.BenchmarkConsoleUtilNotLog 1000000 1339 ns/op
|
||||
//elog.BenchmarkFileLog 100000 26497 ns/op
|
||||
//elog.BenchmarkFileNotLogged 2000000 821 ns/op
|
||||
//elog.BenchmarkFileUtilLog 50000 33945 ns/op
|
||||
//elog.BenchmarkFileUtilNotLog 1000000 1258 ns/op
|
||||
119
vendor/github.com/braintree/manners/helpers_test.go
generated
vendored
Normal file
119
vendor/github.com/braintree/manners/helpers_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
package manners
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// a simple step-controllable http client
|
||||
type client struct {
|
||||
tls bool
|
||||
addr net.Addr
|
||||
connected chan error
|
||||
sendrequest chan bool
|
||||
response chan *rawResponse
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
type rawResponse struct {
|
||||
body []string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *client) Run() {
|
||||
go func() {
|
||||
var err error
|
||||
conn, err := net.Dial(c.addr.Network(), c.addr.String())
|
||||
if err != nil {
|
||||
c.connected <- err
|
||||
return
|
||||
}
|
||||
if c.tls {
|
||||
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
c.connected <- nil
|
||||
for <-c.sendrequest {
|
||||
_, err = conn.Write([]byte("GET / HTTP/1.1\nHost: localhost:8000\n\n"))
|
||||
if err != nil {
|
||||
c.response <- &rawResponse{err: err}
|
||||
}
|
||||
// Read response; no content
|
||||
scanner := bufio.NewScanner(conn)
|
||||
var lines []string
|
||||
for scanner.Scan() {
|
||||
// our null handler doesn't send a body, so we know the request is
|
||||
// done when we reach the blank line after the headers
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
lines = append(lines, line)
|
||||
}
|
||||
c.response <- &rawResponse{lines, scanner.Err()}
|
||||
}
|
||||
conn.Close()
|
||||
ioutil.ReadAll(conn)
|
||||
c.closed <- true
|
||||
}()
|
||||
}
|
||||
|
||||
func newClient(addr net.Addr, tls bool) *client {
|
||||
return &client{
|
||||
addr: addr,
|
||||
tls: tls,
|
||||
connected: make(chan error),
|
||||
sendrequest: make(chan bool),
|
||||
response: make(chan *rawResponse),
|
||||
closed: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// a handler that returns 200 ok with no body
|
||||
var nullHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
func startGenericServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState, runner func() error) (l net.Listener, errc chan error) {
|
||||
server.Addr = "localhost:0"
|
||||
server.Handler = nullHandler
|
||||
if statechanged != nil {
|
||||
// Wrap the ConnState handler with something that will notify
|
||||
// the statechanged channel when a state change happens
|
||||
server.ConnState = func(conn net.Conn, newState http.ConnState) {
|
||||
statechanged <- newState
|
||||
}
|
||||
}
|
||||
|
||||
server.up = make(chan net.Listener)
|
||||
exitchan := make(chan error)
|
||||
|
||||
go func() {
|
||||
exitchan <- runner()
|
||||
}()
|
||||
|
||||
// wait for server socket to be bound
|
||||
select {
|
||||
case l = <-server.up:
|
||||
// all good
|
||||
|
||||
case err := <-exitchan:
|
||||
// all bad
|
||||
t.Fatal("Server failed to start", err)
|
||||
}
|
||||
return l, exitchan
|
||||
}
|
||||
|
||||
func startServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState) (
|
||||
l net.Listener, errc chan error) {
|
||||
return startGenericServer(t, server, statechanged, server.ListenAndServe)
|
||||
}
|
||||
|
||||
func startTLSServer(t *testing.T, server *GracefulServer, certFile, keyFile string, statechanged chan http.ConnState) (l net.Listener, errc chan error) {
|
||||
runner := func() error {
|
||||
return server.ListenAndServeTLS(certFile, keyFile)
|
||||
}
|
||||
|
||||
return startGenericServer(t, server, statechanged, runner)
|
||||
}
|
||||
289
vendor/github.com/braintree/manners/server_test.go
generated
vendored
Normal file
289
vendor/github.com/braintree/manners/server_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
package manners
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
helpers "github.com/braintree/manners/test_helpers"
|
||||
)
|
||||
|
||||
type httpInterface interface {
|
||||
ListenAndServe() error
|
||||
ListenAndServeTLS(certFile, keyFile string) error
|
||||
Serve(listener net.Listener) error
|
||||
}
|
||||
|
||||
// Test that the method signatures of the methods we override from net/http/Server match those of the original.
|
||||
func TestInterface(t *testing.T) {
|
||||
var original, ours interface{}
|
||||
original = &http.Server{}
|
||||
ours = &GracefulServer{}
|
||||
if _, ok := original.(httpInterface); !ok {
|
||||
t.Errorf("httpInterface definition does not match the canonical server!")
|
||||
}
|
||||
if _, ok := ours.(httpInterface); !ok {
|
||||
t.Errorf("GracefulServer does not implement httpInterface")
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the server allows in-flight requests to complete
|
||||
// before shutting down.
|
||||
func TestGracefulness(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
statechanged := make(chan http.ConnState)
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request yet
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
// Even though the client is connected, the server ConnState handler may
|
||||
// not know about that yet. So wait until it is called.
|
||||
waitForState(t, statechanged, http.StateNew, "Request not received")
|
||||
|
||||
server.Close()
|
||||
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting < 1 {
|
||||
t.Errorf("Expected the waitgroup to equal 1 at shutdown; actually %d", waiting)
|
||||
}
|
||||
|
||||
// allow the client to finish sending the request and make sure the server exits after
|
||||
// (client will be in connected but idle state at that point)
|
||||
client.sendrequest <- true
|
||||
close(client.sendrequest)
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that starting the server and closing in 2 new, separate goroutines doesnot
|
||||
// get flagged by the race detector (need to run 'go test' w/the -race flag)
|
||||
func TestRacyClose(t *testing.T) {
|
||||
go func() {
|
||||
ListenAndServe(":9000", nil)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
Close()
|
||||
}()
|
||||
}
|
||||
|
||||
// Tests that the server begins to shut down when told to and does not accept
|
||||
// new requests once shutdown has begun
|
||||
func TestShutdown(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
statechanged := make(chan http.ConnState)
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client1 := newClient(listener.Addr(), false)
|
||||
client1.Run()
|
||||
|
||||
// wait for client1 to connect
|
||||
if err := <-client1.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
// Even though the client is connected, the server ConnState handler may
|
||||
// not know about that yet. So wait until it is called.
|
||||
waitForState(t, statechanged, http.StateNew, "Request not received")
|
||||
|
||||
// start the shutdown; once it hits waitgroup.Wait()
|
||||
// the listener should of been closed, though client1 is still connected
|
||||
if server.Close() != true {
|
||||
t.Fatal("first call to Close returned false")
|
||||
}
|
||||
if server.Close() != false {
|
||||
t.Fatal("second call to Close returned true")
|
||||
}
|
||||
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 1 {
|
||||
t.Errorf("Waitcount should be one, got %d", waiting)
|
||||
}
|
||||
|
||||
// should get connection refused at this point
|
||||
client2 := newClient(listener.Addr(), false)
|
||||
client2.Run()
|
||||
|
||||
if err := <-client2.connected; err == nil {
|
||||
t.Fatal("client2 connected when it should of received connection refused")
|
||||
}
|
||||
|
||||
// let client1 finish so the server can exit
|
||||
close(client1.sendrequest) // don't bother sending an actual request
|
||||
|
||||
<-exitchan
|
||||
}
|
||||
|
||||
// If a request is sent to a closed server via a kept alive connection then
|
||||
// the server closes the connection upon receiving the request.
|
||||
func TestRequestAfterClose(t *testing.T) {
|
||||
// Given
|
||||
server := NewServer()
|
||||
srvStateChangedCh := make(chan http.ConnState, 100)
|
||||
listener, srvClosedCh := startServer(t, server, srvStateChangedCh)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
<-client.connected
|
||||
client.sendrequest <- true
|
||||
<-client.response
|
||||
|
||||
server.Close()
|
||||
if err := <-srvClosedCh; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
|
||||
// When
|
||||
client.sendrequest <- true
|
||||
rr := <-client.response
|
||||
|
||||
// Then
|
||||
if rr.body != nil || rr.err != nil {
|
||||
t.Errorf("Request should be rejected, body=%v, err=%v", rr.body, rr.err)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForState(t *testing.T, waiter chan http.ConnState, state http.ConnState, errmsg string) {
|
||||
for {
|
||||
select {
|
||||
case ns := <-waiter:
|
||||
if ns == state {
|
||||
return
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal(errmsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a request moving from active->idle->active using an actual
|
||||
// network connection still results in a corect shutdown
|
||||
func TestStateTransitionActiveIdleActive(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
statechanged := make(chan http.ConnState)
|
||||
server.wg = wg
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
client.sendrequest <- true
|
||||
waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
|
||||
<-client.response
|
||||
waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
|
||||
}
|
||||
|
||||
// client is now in an idle state
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 0 {
|
||||
t.Errorf("Waitcount should be zero, got %d", waiting)
|
||||
}
|
||||
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test state transitions from new->active->-idle->closed using an actual
|
||||
// network connection and make sure the waitgroup count is correct at the end.
|
||||
func TestStateTransitionActiveIdleClosed(t *testing.T) {
|
||||
var (
|
||||
listener net.Listener
|
||||
exitchan chan error
|
||||
)
|
||||
|
||||
keyFile, err1 := helpers.NewTempFile(helpers.Key)
|
||||
certFile, err2 := helpers.NewTempFile(helpers.Cert)
|
||||
defer keyFile.Unlink()
|
||||
defer certFile.Unlink()
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
t.Fatal("Failed to create temporary files", err1, err2)
|
||||
}
|
||||
|
||||
for _, withTLS := range []bool{false, true} {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
statechanged := make(chan http.ConnState)
|
||||
server.wg = wg
|
||||
if withTLS {
|
||||
listener, exitchan = startTLSServer(t, server, certFile.Name(), keyFile.Name(), statechanged)
|
||||
} else {
|
||||
listener, exitchan = startServer(t, server, statechanged)
|
||||
}
|
||||
|
||||
client := newClient(listener.Addr(), withTLS)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
|
||||
client.sendrequest <- true
|
||||
waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
|
||||
|
||||
rr := <-client.response
|
||||
if rr.err != nil {
|
||||
t.Fatalf("tls=%t unexpected error from client %s", withTLS, rr.err)
|
||||
}
|
||||
|
||||
waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
|
||||
|
||||
// client is now in an idle state
|
||||
close(client.sendrequest)
|
||||
<-client.closed
|
||||
waitForState(t, statechanged, http.StateClosed, "Client failed to reach closed state")
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 0 {
|
||||
t.Errorf("Waitcount should be zero, got %d", waiting)
|
||||
}
|
||||
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoutinesCount(t *testing.T) {
|
||||
var count int
|
||||
server := NewServer()
|
||||
|
||||
count = server.RoutinesCount()
|
||||
if count != 0 {
|
||||
t.Errorf("Expected the routines count to equal 0; actually %d", count)
|
||||
}
|
||||
|
||||
server.StartRoutine()
|
||||
count = server.RoutinesCount()
|
||||
if count != 1 {
|
||||
t.Errorf("Expected the routines count to equal 1; actually %d", count)
|
||||
}
|
||||
|
||||
server.FinishRoutine()
|
||||
count = server.RoutinesCount()
|
||||
if count != 0 {
|
||||
t.Errorf("Expected the routines count to equal 0; actually %d", count)
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/braintree/manners/test_helpers/certs.go
generated
vendored
Normal file
29
vendor/github.com/braintree/manners/test_helpers/certs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package test_helpers
|
||||
|
||||
// A PEM-encoded TLS cert with SAN IPs "127.0.0.1" and "[::1]", expiring at the
|
||||
// last second of 2049 (the end of ASN.1 time).
|
||||
|
||||
// generated from src/pkg/crypto/tls:
|
||||
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var (
|
||||
Cert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
Key = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
)
|
||||
13
vendor/github.com/braintree/manners/test_helpers/conn.go
generated
vendored
Normal file
13
vendor/github.com/braintree/manners/test_helpers/conn.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package test_helpers
|
||||
|
||||
import "net"
|
||||
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
CloseCalled bool
|
||||
}
|
||||
|
||||
func (c *Conn) Close() error {
|
||||
c.CloseCalled = true
|
||||
return nil
|
||||
}
|
||||
34
vendor/github.com/braintree/manners/test_helpers/listener.go
generated
vendored
Normal file
34
vendor/github.com/braintree/manners/test_helpers/listener.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package test_helpers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
AcceptRelease chan bool
|
||||
CloseCalled chan bool
|
||||
}
|
||||
|
||||
func NewListener() *Listener {
|
||||
return &Listener{
|
||||
make(chan bool, 1),
|
||||
make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
|
||||
return addr
|
||||
}
|
||||
|
||||
func (l *Listener) Close() error {
|
||||
l.CloseCalled <- true
|
||||
l.AcceptRelease <- true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Listener) Accept() (net.Conn, error) {
|
||||
<-l.AcceptRelease
|
||||
return nil, errors.New("connection closed")
|
||||
}
|
||||
27
vendor/github.com/braintree/manners/test_helpers/temp_file.go
generated
vendored
Normal file
27
vendor/github.com/braintree/manners/test_helpers/temp_file.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package test_helpers
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type TempFile struct {
|
||||
*os.File
|
||||
}
|
||||
|
||||
func NewTempFile(content []byte) (*TempFile, error) {
|
||||
f, err := ioutil.TempFile("", "graceful-test")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.Write(content)
|
||||
return &TempFile{f}, nil
|
||||
}
|
||||
|
||||
func (tf *TempFile) Unlink() {
|
||||
if tf.File != nil {
|
||||
os.Remove(tf.Name())
|
||||
tf.File = nil
|
||||
}
|
||||
}
|
||||
33
vendor/github.com/braintree/manners/test_helpers/wait_group.go
generated
vendored
Normal file
33
vendor/github.com/braintree/manners/test_helpers/wait_group.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package test_helpers
|
||||
|
||||
import "sync"
|
||||
|
||||
type WaitGroup struct {
|
||||
sync.Mutex
|
||||
Count int
|
||||
WaitCalled chan int
|
||||
}
|
||||
|
||||
func NewWaitGroup() *WaitGroup {
|
||||
return &WaitGroup{
|
||||
WaitCalled: make(chan int, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Add(delta int) {
|
||||
wg.Lock()
|
||||
wg.Count++
|
||||
wg.Unlock()
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Done() {
|
||||
wg.Lock()
|
||||
wg.Count--
|
||||
wg.Unlock()
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Wait() {
|
||||
wg.Lock()
|
||||
wg.WaitCalled <- wg.Count
|
||||
wg.Unlock()
|
||||
}
|
||||
54
vendor/github.com/braintree/manners/transition_test.go
generated
vendored
Normal file
54
vendor/github.com/braintree/manners/transition_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package manners
|
||||
|
||||
import (
|
||||
helpers "github.com/braintree/manners/test_helpers"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStateTransitions(t *testing.T) {
|
||||
tests := []transitionTest{
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive}, 1},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateHijacked}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive}, 1},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle, http.StateClosed}, 0},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
testStateTransition(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
type transitionTest struct {
|
||||
states []http.ConnState
|
||||
expectedWgCount int
|
||||
}
|
||||
|
||||
func testStateTransition(t *testing.T, test transitionTest) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
startServer(t, server, nil)
|
||||
|
||||
conn := &helpers.Conn{}
|
||||
for _, newState := range test.states {
|
||||
server.ConnState(conn, newState)
|
||||
}
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != test.expectedWgCount {
|
||||
names := make([]string, len(test.states))
|
||||
for i, s := range test.states {
|
||||
names[i] = s.String()
|
||||
}
|
||||
transitions := strings.Join(names, " -> ")
|
||||
t.Errorf("%s - Waitcount should be %d, got %d", transitions, test.expectedWgCount, waiting)
|
||||
}
|
||||
}
|
||||
5
vendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat
generated
vendored
Executable file
5
vendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat
generated
vendored
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
git fetch
|
||||
git checkout %GIT_COMMIT%
|
||||
|
||||
SET GOPATH=%CD%\Godeps\_workspace;c:\Users\Administrator\go
|
||||
c:\Go\bin\go test -v .
|
||||
13
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go
generated
vendored
Normal file
13
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package jibber_jabber_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJibberJabber(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Jibber Jabber Suite")
|
||||
}
|
||||
104
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go
generated
vendored
Normal file
104
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// +build darwin freebsd linux netbsd openbsd
|
||||
|
||||
package jibber_jabber_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/cloudfoundry/jibber_jabber"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Unix", func() {
|
||||
AfterEach(func() {
|
||||
os.Setenv("LC_ALL", "")
|
||||
os.Setenv("LANG", "en_US.UTF-8")
|
||||
})
|
||||
|
||||
Describe("#DetectIETF", func() {
|
||||
Context("Returns IETF encoded locale", func() {
|
||||
It("should return the locale set to LC_ALL", func() {
|
||||
os.Setenv("LC_ALL", "fr_FR.UTF-8")
|
||||
result, _ := DetectIETF()
|
||||
Ω(result).Should(Equal("fr-FR"))
|
||||
})
|
||||
|
||||
It("should return the locale set to LANG if LC_ALL isn't set", func() {
|
||||
os.Setenv("LANG", "fr_FR.UTF-8")
|
||||
|
||||
result, _ := DetectIETF()
|
||||
Ω(result).Should(Equal("fr-FR"))
|
||||
})
|
||||
|
||||
It("should return an error if it cannot detect a locale", func() {
|
||||
os.Setenv("LANG", "")
|
||||
|
||||
_, err := DetectIETF()
|
||||
Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the locale is simply 'fr'", func() {
|
||||
BeforeEach(func() {
|
||||
os.Setenv("LANG", "fr")
|
||||
})
|
||||
|
||||
It("should return the locale without a territory", func() {
|
||||
language, err := DetectIETF()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(language).Should(Equal("fr"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("#DetectLanguage", func() {
|
||||
Context("Returns encoded language", func() {
|
||||
It("should return the language set to LC_ALL", func() {
|
||||
os.Setenv("LC_ALL", "fr_FR.UTF-8")
|
||||
result, _ := DetectLanguage()
|
||||
Ω(result).Should(Equal("fr"))
|
||||
})
|
||||
|
||||
It("should return the language set to LANG if LC_ALL isn't set", func() {
|
||||
os.Setenv("LANG", "fr_FR.UTF-8")
|
||||
|
||||
result, _ := DetectLanguage()
|
||||
Ω(result).Should(Equal("fr"))
|
||||
})
|
||||
|
||||
It("should return an error if it cannot detect a language", func() {
|
||||
os.Setenv("LANG", "")
|
||||
|
||||
_, err := DetectLanguage()
|
||||
Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("#DetectTerritory", func() {
|
||||
Context("Returns encoded territory", func() {
|
||||
It("should return the territory set to LC_ALL", func() {
|
||||
os.Setenv("LC_ALL", "fr_FR.UTF-8")
|
||||
result, _ := DetectTerritory()
|
||||
Ω(result).Should(Equal("FR"))
|
||||
})
|
||||
|
||||
It("should return the territory set to LANG if LC_ALL isn't set", func() {
|
||||
os.Setenv("LANG", "fr_FR.UTF-8")
|
||||
|
||||
result, _ := DetectTerritory()
|
||||
Ω(result).Should(Equal("FR"))
|
||||
})
|
||||
|
||||
It("should return an error if it cannot detect a territory", func() {
|
||||
os.Setenv("LANG", "")
|
||||
|
||||
_, err := DetectTerritory()
|
||||
Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
51
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go
generated
vendored
Normal file
51
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// +build windows
|
||||
|
||||
package jibber_jabber_test
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
. "github.com/cloudfoundry/jibber_jabber"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
const (
|
||||
LOCALE_REGEXP = "^[a-z]{2}-[A-Z]{2}$"
|
||||
LANGUAGE_REGEXP = "^[a-z]{2}$"
|
||||
TERRITORY_REGEXP = "^[A-Z]{2}$"
|
||||
)
|
||||
|
||||
var _ = Describe("Windows", func() {
|
||||
BeforeEach(func() {
|
||||
locale, err := DetectIETF()
|
||||
Ω(err).Should(BeNil())
|
||||
Ω(locale).ShouldNot(BeNil())
|
||||
Ω(locale).ShouldNot(Equal(""))
|
||||
})
|
||||
|
||||
Describe("#DetectIETF", func() {
|
||||
It("detects correct IETF locale", func() {
|
||||
locale, _ := DetectIETF()
|
||||
matched, _ := regexp.MatchString(LOCALE_REGEXP, locale)
|
||||
Ω(matched).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("#DetectLanguage", func() {
|
||||
It("detects correct Language", func() {
|
||||
language, _ := DetectLanguage()
|
||||
matched, _ := regexp.MatchString(LANGUAGE_REGEXP, language)
|
||||
Ω(matched).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("#DetectTerritory", func() {
|
||||
It("detects correct Territory", func() {
|
||||
territory, _ := DetectTerritory()
|
||||
matched, _ := regexp.MatchString(TERRITORY_REGEXP, territory)
|
||||
Ω(matched).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
251
vendor/github.com/dgryski/dgoogauth/googauth_test.go
generated
vendored
Normal file
251
vendor/github.com/dgryski/dgoogauth/googauth_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
package dgoogauth
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Test vectors via:
|
||||
// http://code.google.com/p/google-authenticator/source/browse/libpam/pam_google_authenticator_unittest.c
|
||||
// https://google-authenticator.googlecode.com/hg/libpam/totp.html
|
||||
|
||||
var codeTests = []struct {
|
||||
secret string
|
||||
value int64
|
||||
code int
|
||||
}{
|
||||
{"2SH3V3GDW7ZNMGYE", 1, 293240},
|
||||
{"2SH3V3GDW7ZNMGYE", 5, 932068},
|
||||
{"2SH3V3GDW7ZNMGYE", 10000, 50548},
|
||||
}
|
||||
|
||||
func TestCode(t *testing.T) {
|
||||
|
||||
for _, v := range codeTests {
|
||||
c := ComputeCode(v.secret, v.value)
|
||||
|
||||
if c != v.code {
|
||||
t.Errorf("computeCode(%s, %d): got %d expected %d\n", v.secret, v.value, c, v.code)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestScratchCode(t *testing.T) {
|
||||
|
||||
var cotp OTPConfig
|
||||
|
||||
cotp.ScratchCodes = []int{11112222, 22223333}
|
||||
|
||||
var scratchTests = []struct {
|
||||
code int
|
||||
result bool
|
||||
}{
|
||||
{33334444, false},
|
||||
{11112222, true},
|
||||
{11112222, false},
|
||||
{22223333, true},
|
||||
{22223333, false},
|
||||
{33334444, false},
|
||||
}
|
||||
|
||||
for _, s := range scratchTests {
|
||||
r := cotp.checkScratchCodes(s.code)
|
||||
if r != s.result {
|
||||
t.Errorf("scratchcode(%d) failed: got %t expected %t", s.code, r, s.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHotpCode(t *testing.T) {
|
||||
|
||||
var cotp OTPConfig
|
||||
|
||||
// reuse our test values from above
|
||||
// perhaps create more?
|
||||
cotp.Secret = "2SH3V3GDW7ZNMGYE"
|
||||
cotp.HotpCounter = 1
|
||||
cotp.WindowSize = 3
|
||||
|
||||
var counterCodes = []struct {
|
||||
code int
|
||||
result bool
|
||||
counter int
|
||||
}{
|
||||
{ /* 1 */ 293240, true, 2}, // increments on success
|
||||
{ /* 1 */ 293240, false, 3}, // and failure
|
||||
{ /* 5 */ 932068, true, 6}, // inside of window
|
||||
{ /* 10 */ 481725, false, 7}, // outside of window
|
||||
{ /* 10 */ 481725, false, 8}, // outside of window
|
||||
{ /* 10 */ 481725, true, 11}, // now inside of window
|
||||
}
|
||||
|
||||
for i, s := range counterCodes {
|
||||
r := cotp.checkHotpCode(s.code)
|
||||
if r != s.result {
|
||||
t.Errorf("counterCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
|
||||
}
|
||||
if cotp.HotpCounter != s.counter {
|
||||
t.Errorf("hotpCounter incremented poorly: got %d expected %d", cotp.HotpCounter, s.counter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotpCode(t *testing.T) {
|
||||
|
||||
var cotp OTPConfig
|
||||
|
||||
// reuse our test values from above
|
||||
cotp.Secret = "2SH3V3GDW7ZNMGYE"
|
||||
cotp.WindowSize = 5
|
||||
|
||||
var windowTest = []struct {
|
||||
code int
|
||||
t0 int
|
||||
result bool
|
||||
}{
|
||||
{50548, 9997, false},
|
||||
{50548, 9998, true},
|
||||
{50548, 9999, true},
|
||||
{50548, 10000, true},
|
||||
{50548, 10001, true},
|
||||
{50548, 10002, true},
|
||||
{50548, 10003, false},
|
||||
}
|
||||
|
||||
for i, s := range windowTest {
|
||||
r := cotp.checkTotpCode(s.t0, s.code)
|
||||
if r != s.result {
|
||||
t.Errorf("counterCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
|
||||
}
|
||||
}
|
||||
|
||||
cotp.DisallowReuse = make([]int, 0)
|
||||
var noreuseTest = []struct {
|
||||
code int
|
||||
t0 int
|
||||
result bool
|
||||
disallowed []int
|
||||
}{
|
||||
{50548 /* 10000 */, 9997, false, []int{}},
|
||||
{50548 /* 10000 */, 9998, true, []int{10000}},
|
||||
{50548 /* 10000 */, 9999, false, []int{10000}},
|
||||
{478726 /* 10001 */, 10001, true, []int{10000, 10001}},
|
||||
{646986 /* 10002 */, 10002, true, []int{10000, 10001, 10002}},
|
||||
{842639 /* 10003 */, 10003, true, []int{10001, 10002, 10003}},
|
||||
}
|
||||
|
||||
for i, s := range noreuseTest {
|
||||
r := cotp.checkTotpCode(s.t0, s.code)
|
||||
if r != s.result {
|
||||
t.Errorf("timeCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
|
||||
}
|
||||
if len(cotp.DisallowReuse) != len(s.disallowed) {
|
||||
t.Errorf("timeCode(%d) (step %d) failed: disallowReuse len mismatch: got %d expected %d", s.code, i, len(cotp.DisallowReuse), len(s.disallowed))
|
||||
} else {
|
||||
same := true
|
||||
for j := range s.disallowed {
|
||||
if s.disallowed[j] != cotp.DisallowReuse[j] {
|
||||
same = false
|
||||
}
|
||||
}
|
||||
if !same {
|
||||
t.Errorf("timeCode(%d) (step %d) failed: disallowReused: got %v expected %v", s.code, i, cotp.DisallowReuse, s.disallowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
|
||||
otpconf := &OTPConfig{
|
||||
Secret: "2SH3V3GDW7ZNMGYE",
|
||||
WindowSize: 3,
|
||||
HotpCounter: 1,
|
||||
ScratchCodes: []int{11112222, 22223333},
|
||||
}
|
||||
|
||||
type attempt struct {
|
||||
code string
|
||||
result bool
|
||||
}
|
||||
|
||||
var attempts = []attempt{
|
||||
{"foobar", false}, // not digits
|
||||
{"1fooba", false}, // not valid number
|
||||
{"1111111", false}, // bad length
|
||||
{ /* 1 */ "293240", true}, // hopt increments on success
|
||||
{ /* 1 */ "293240", false}, // hopt failure
|
||||
{"33334444", false}, // scratch
|
||||
{"11112222", true},
|
||||
{"11112222", false},
|
||||
}
|
||||
|
||||
for _, a := range attempts {
|
||||
r, _ := otpconf.Authenticate(a.code)
|
||||
if r != a.result {
|
||||
t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
|
||||
}
|
||||
}
|
||||
|
||||
// let's check some time-based codes
|
||||
otpconf.HotpCounter = 0
|
||||
// I haven't mocked the clock, so we'll just compute one
|
||||
var t0 int64
|
||||
if otpconf.UTC {
|
||||
t0 = int64(time.Now().UTC().Unix() / 30)
|
||||
} else {
|
||||
t0 = int64(time.Now().Unix() / 30)
|
||||
}
|
||||
c := ComputeCode(otpconf.Secret, t0)
|
||||
|
||||
invalid := c + 1
|
||||
attempts = []attempt{
|
||||
{strconv.Itoa(invalid), false},
|
||||
{strconv.Itoa(c), true},
|
||||
}
|
||||
|
||||
for _, a := range attempts {
|
||||
r, _ := otpconf.Authenticate(a.code)
|
||||
if r != a.result {
|
||||
t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
|
||||
}
|
||||
|
||||
otpconf.UTC = true
|
||||
r, _ = otpconf.Authenticate(a.code)
|
||||
if r != a.result {
|
||||
t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
|
||||
}
|
||||
otpconf.UTC = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestProvisionURI(t *testing.T) {
|
||||
otpconf := OTPConfig{
|
||||
Secret: "x",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
user, iss string
|
||||
hotp bool
|
||||
out string
|
||||
}{
|
||||
{"test", "", false, "otpauth://totp/test?secret=x"},
|
||||
{"test", "", true, "otpauth://hotp/test?counter=1&secret=x"},
|
||||
{"test", "Company", true, "otpauth://hotp/Company:test?counter=1&issuer=Company&secret=x"},
|
||||
{"test", "Company", false, "otpauth://totp/Company:test?issuer=Company&secret=x"},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
otpconf.HotpCounter = 0
|
||||
if c.hotp {
|
||||
otpconf.HotpCounter = 1
|
||||
}
|
||||
got := otpconf.ProvisionURIWithIssuer(c.user, c.iss)
|
||||
if got != c.out {
|
||||
t.Errorf("%d: want %q, got %q", i, c.out, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
504
vendor/github.com/disintegration/imaging/adjust_test.go
generated
vendored
Normal file
504
vendor/github.com/disintegration/imaging/adjust_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGrayscale(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Grayscale 3x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x3d, 0x3d, 0x3d, 0x01, 0x78, 0x78, 0x78, 0x02, 0x17, 0x17, 0x17, 0x03,
|
||||
0x1f, 0x1f, 0x1f, 0xff, 0x25, 0x25, 0x25, 0xff, 0x66, 0x66, 0x66, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Grayscale(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvert(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Invert 3x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x33, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x02, 0xff, 0xff, 0x33, 0x03,
|
||||
0xee, 0xdd, 0xcc, 0xff, 0xcc, 0xdd, 0xee, 0xff, 0x55, 0xcc, 0x44, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Invert(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustContrast(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustContrast 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xd5, 0x00, 0x00, 0x01, 0x00, 0xd5, 0x00, 0x02, 0x00, 0x00, 0xd5, 0x03,
|
||||
0x05, 0x18, 0x2b, 0xff, 0x2b, 0x18, 0x05, 0xff, 0xaf, 0x2b, 0xc2, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0xff, 0x03,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 -10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xc4, 0x0d, 0x0d, 0x01, 0x0d, 0xc4, 0x0d, 0x02, 0x0d, 0x0d, 0xc4, 0x03,
|
||||
0x1c, 0x2b, 0x3b, 0xff, 0x3b, 0x2b, 0x1c, 0xff, 0xa6, 0x3b, 0xb5, 0xff,
|
||||
0x0d, 0x0d, 0x0d, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xf2, 0xf2, 0xf2, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 -100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x80, 0x80, 0x80, 0x01, 0x80, 0x80, 0x80, 0x02, 0x80, 0x80, 0x80, 0x03,
|
||||
0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
|
||||
0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustContrast(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustBrightness(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustBrightness 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xe6, 0x1a, 0x1a, 0x01, 0x1a, 0xe6, 0x1a, 0x02, 0x1a, 0x1a, 0xe6, 0x03,
|
||||
0x2b, 0x3c, 0x4d, 0xff, 0x4d, 0x3c, 0x2b, 0xff, 0xc4, 0x4d, 0xd5, 0xff,
|
||||
0x1a, 0x1a, 0x1a, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x03,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 -10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xb3, 0x00, 0x00, 0x01, 0x00, 0xb3, 0x00, 0x02, 0x00, 0x00, 0xb3, 0x03,
|
||||
0x00, 0x09, 0x1a, 0xff, 0x1a, 0x09, 0x00, 0xff, 0x91, 0x1a, 0xa2, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 -100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustBrightness(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustGamma(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustGamma 3x3 0.75",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.75,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xbd, 0x00, 0x00, 0x01, 0x00, 0xbd, 0x00, 0x02, 0x00, 0x00, 0xbd, 0x03,
|
||||
0x07, 0x11, 0x1e, 0xff, 0x1e, 0x11, 0x07, 0xff, 0x95, 0x1e, 0xa9, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustGamma 3x3 1.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xdc, 0x00, 0x00, 0x01, 0x00, 0xdc, 0x00, 0x02, 0x00, 0x00, 0xdc, 0x03,
|
||||
0x2a, 0x43, 0x57, 0xff, 0x57, 0x43, 0x2a, 0xff, 0xc3, 0x57, 0xcf, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x57, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustGamma 3x3 1.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustGamma(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustSigmoid(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
m float64
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 3.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
3.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xd4, 0x00, 0x00, 0x01, 0x00, 0xd4, 0x00, 0x02, 0x00, 0x00, 0xd4, 0x03,
|
||||
0x0d, 0x1b, 0x2b, 0xff, 0x2b, 0x1b, 0x0d, 0xff, 0xb1, 0x2b, 0xc3, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 -3.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
-3.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xc4, 0x00, 0x00, 0x01, 0x00, 0xc4, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x03,
|
||||
0x16, 0x2a, 0x3b, 0xff, 0x3b, 0x2a, 0x16, 0xff, 0xa4, 0x3b, 0xb3, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 0.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
0.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustSigmoid(d.src, d.m, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
190
vendor/github.com/disintegration/imaging/effects_test.go
generated
vendored
Normal file
190
vendor/github.com/disintegration/imaging/effects_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBlur(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
sigma float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Blur 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
0.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Blur 3x3 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x01, 0x02, 0x04, 0x04, 0x0a, 0x10, 0x18, 0x18, 0x01, 0x02, 0x04, 0x04,
|
||||
0x09, 0x10, 0x18, 0x18, 0x3f, 0x69, 0x9e, 0x9e, 0x09, 0x10, 0x18, 0x18,
|
||||
0x01, 0x02, 0x04, 0x04, 0x0a, 0x10, 0x18, 0x18, 0x01, 0x02, 0x04, 0x04,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Blur 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
|
||||
0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
|
||||
0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Blur(d.src, d.sigma)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharpen(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
sigma float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Sharpen 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x3 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
|
||||
0x64, 0x64, 0x64, 0x64, 0x7e, 0x7e, 0x7e, 0x7e, 0x64, 0x64, 0x64, 0x64,
|
||||
0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x86, 0x86, 0x86, 0x86, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x1 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 0),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 1),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Sharpen(d.src, d.sigma)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
399
vendor/github.com/disintegration/imaging/helpers_test.go
generated
vendored
Normal file
399
vendor/github.com/disintegration/imaging/helpers_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func compareNRGBA(img1, img2 *image.NRGBA, delta int) bool {
|
||||
if !img1.Rect.Eq(img2.Rect) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(img1.Pix) != len(img2.Pix) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(img1.Pix); i++ {
|
||||
if absint(int(img1.Pix[i])-int(img2.Pix[i])) > delta {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
imgWithAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
|
||||
imgWithAlpha.Pix = []uint8{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
|
||||
244, 245, 246, 247, 248, 249, 250, 252, 252, 253, 254, 255,
|
||||
}
|
||||
|
||||
imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
|
||||
imgWithoutAlpha.Pix = []uint8{
|
||||
0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 10, 255,
|
||||
127, 128, 129, 255, 131, 132, 133, 255, 135, 136, 137, 255,
|
||||
244, 245, 246, 255, 248, 249, 250, 255, 252, 253, 254, 255,
|
||||
}
|
||||
|
||||
for _, format := range []Format{JPEG, PNG, GIF, BMP, TIFF} {
|
||||
img := imgWithoutAlpha
|
||||
if format == PNG {
|
||||
img = imgWithAlpha
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := Encode(buf, img, format)
|
||||
if err != nil {
|
||||
t.Errorf("fail encoding format %s", format)
|
||||
continue
|
||||
}
|
||||
|
||||
img2, err := Decode(buf)
|
||||
if err != nil {
|
||||
t.Errorf("fail decoding format %s", format)
|
||||
continue
|
||||
}
|
||||
img2cloned := Clone(img2)
|
||||
|
||||
delta := 0
|
||||
if format == JPEG {
|
||||
delta = 3
|
||||
} else if format == GIF {
|
||||
delta = 16
|
||||
}
|
||||
|
||||
if !compareNRGBA(img, img2cloned, delta) {
|
||||
t.Errorf("test [DecodeEncode %s] failed: %#v %#v", format, img, img2cloned)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := Encode(buf, imgWithAlpha, JPEG)
|
||||
if err != nil {
|
||||
t.Errorf("failed encoding alpha to JPEG format %s", err)
|
||||
}
|
||||
|
||||
buf = &bytes.Buffer{}
|
||||
err = Encode(buf, imgWithAlpha, Format(100))
|
||||
if err != ErrUnsupportedFormat {
|
||||
t.Errorf("expected ErrUnsupportedFormat")
|
||||
}
|
||||
|
||||
buf = bytes.NewBuffer([]byte("bad data"))
|
||||
_, err = Decode(buf)
|
||||
if err == nil {
|
||||
t.Errorf("decoding bad data, expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
w, h int
|
||||
c color.Color
|
||||
dstBounds image.Rectangle
|
||||
dstPix []uint8
|
||||
}{
|
||||
{
|
||||
"New 1x1 black",
|
||||
1, 1,
|
||||
color.NRGBA{0, 0, 0, 0},
|
||||
image.Rect(0, 0, 1, 1),
|
||||
[]uint8{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
{
|
||||
"New 1x2 red",
|
||||
1, 2,
|
||||
color.NRGBA{255, 0, 0, 255},
|
||||
image.Rect(0, 0, 1, 2),
|
||||
[]uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff},
|
||||
},
|
||||
{
|
||||
"New 2x1 white",
|
||||
2, 1,
|
||||
color.NRGBA{255, 255, 255, 255},
|
||||
image.Rect(0, 0, 2, 1),
|
||||
[]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
"New 0x0 white",
|
||||
0, 0,
|
||||
color.NRGBA{255, 255, 255, 255},
|
||||
image.Rect(0, 0, 0, 0),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := New(d.w, d.h, d.c)
|
||||
want := image.NewNRGBA(d.dstBounds)
|
||||
want.Pix = d.dstPix
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Clone NRGBA",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone NRGBA64",
|
||||
&image.NRGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA",
|
||||
&image.RGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA64",
|
||||
&image.RGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray",
|
||||
&image.Gray{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray16",
|
||||
&image.Gray16{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 2,
|
||||
Pix: []uint8{0x11, 0x11, 0xee, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Alpha",
|
||||
&image.Alpha{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr",
|
||||
&image.YCbCr{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
YStride: 6,
|
||||
CStride: 6,
|
||||
Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
|
||||
Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
|
||||
Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 444",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 440",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio440,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 422",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
|
||||
Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 420",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
|
||||
Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
|
||||
YStride: 4, CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Paletted",
|
||||
&image.Paletted{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
Stride: 6 * 1,
|
||||
Palette: color.Palette{
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
|
||||
},
|
||||
Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := Clone(d.src)
|
||||
want := d.want
|
||||
|
||||
delta := 0
|
||||
if _, ok := d.src.(*image.YCbCr); ok {
|
||||
delta = 1
|
||||
}
|
||||
|
||||
if !compareNRGBA(got, want, delta) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormats(t *testing.T) {
|
||||
formatNames := map[Format]string{
|
||||
JPEG: "JPEG",
|
||||
PNG: "PNG",
|
||||
GIF: "GIF",
|
||||
BMP: "BMP",
|
||||
TIFF: "TIFF",
|
||||
Format(-1): "Unsupported",
|
||||
}
|
||||
for format, name := range formatNames {
|
||||
got := format.String()
|
||||
if got != name {
|
||||
t.Errorf("test [Format names] failed: got %#v want %#v", got, name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
570
vendor/github.com/disintegration/imaging/resize_test.go
generated
vendored
Normal file
570
vendor/github.com/disintegration/imaging/resize_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResize(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Resize 2x2 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 2x2 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 3x1 1x1 nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 0),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0xff, 0x00, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 0x4 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 4,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 4x0 linear",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
4, 0,
|
||||
Linear,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xbf, 0x00, 0x00, 0xbf, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0x40, 0x00, 0x40, 0x30, 0x30, 0x10, 0x70, 0x8f, 0x10, 0x30, 0xcf, 0xbf, 0x00, 0x40, 0xff,
|
||||
0x00, 0xbf, 0x00, 0xbf, 0x10, 0x8f, 0x30, 0xcf, 0x30, 0x30, 0x8f, 0xef, 0x40, 0x00, 0xbf, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xbf, 0x40, 0xff, 0x00, 0x40, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 0x0 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, -1, -1),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 0x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 -1x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-1, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Resize(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 1) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
|
||||
for i, filter := range []ResampleFilter{
|
||||
NearestNeighbor,
|
||||
Box,
|
||||
Linear,
|
||||
Hermite,
|
||||
MitchellNetravali,
|
||||
CatmullRom,
|
||||
BSpline,
|
||||
Gaussian,
|
||||
Lanczos,
|
||||
Hann,
|
||||
Hamming,
|
||||
Blackman,
|
||||
Bartlett,
|
||||
Welch,
|
||||
Cosine,
|
||||
} {
|
||||
src := image.NewNRGBA(image.Rect(-1, -1, 2, 3))
|
||||
got := Resize(src, 5, 6, filter)
|
||||
want := image.NewNRGBA(image.Rect(0, 0, 5, 6))
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [Resize all filters #%d] failed: %#v", i, got)
|
||||
}
|
||||
|
||||
if filter.Kernel != nil {
|
||||
x := filter.Kernel(filter.Support + 0.0001)
|
||||
if x != 0 {
|
||||
t.Errorf("test [ResampleFilter edge cases #%d] failed: %f", i, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bcs2 := bcspline(2, 1, 0)
|
||||
if bcs2 != 0 {
|
||||
t.Errorf("test [bcspline 2] failed: %f", bcs2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFit(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Fit 2x2 1x10 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 10,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 10x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 10x10 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10, 10,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 0x0 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, -1, -1),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 0x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 -1x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-1, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Fit(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFill(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
a Anchor
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Fill 4x4 2x2 Center Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Center,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 1x4 TopLeft Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
1, 4,
|
||||
TopLeft,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 4),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
0x20, 0x21, 0x22, 0x23,
|
||||
0x30, 0x31, 0x32, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 8x2 Bottom Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
8, 2,
|
||||
Bottom,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 8, 2),
|
||||
Stride: 8 * 4,
|
||||
Pix: []uint8{
|
||||
0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 2x8 Top Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 8,
|
||||
Top,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 8),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 4x4 TopRight Box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
4, 4,
|
||||
TopRight,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 0x4 Left Box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 4,
|
||||
Left,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fill 0x0 4x4 Right Box",
|
||||
&image.NRGBA{},
|
||||
4, 4,
|
||||
Right,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Fill(d.src, d.w, d.h, d.a, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestThumbnail(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Thumbnail 6x2 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 5, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Thumbnail 2x6 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 5),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Thumbnail 1x3 2x2 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Thumbnail(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
652
vendor/github.com/disintegration/imaging/tools_test.go
generated
vendored
Normal file
652
vendor/github.com/disintegration/imaging/tools_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCrop(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
r image.Rectangle
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Crop 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
image.Rect(-1, 0, 1, 1),
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Crop(d.src, d.r)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCropCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"CropCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
2, 1,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropCenter 2x3 0x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
0, 1,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropCenter 2x3 5x5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
5, 5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := CropCenter(d.src, d.w, d.h)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCropAnchor(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
anchor Anchor
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"CropAnchor 4x4 2x2 TopLeft",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
TopLeft,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Top",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Top,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 TopRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
TopRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Left",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Left,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Center",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Center,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Right",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Right,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 BottomLeft",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
BottomLeft,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Bottom",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Bottom,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 0x0 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 100x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
100, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 1x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
1, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 4),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 0x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := CropAnchor(d.src, d.w, d.h, d.anchor)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaste(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
p image.Point
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Paste 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, 0),
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Paste(d.src1, d.src2, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasteCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"PasteCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := PasteCenter(d.src1, d.src2)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlay(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
p image.Point
|
||||
a float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Overlay 2x3 2x1 1.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, 0),
|
||||
1.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Overlay 2x2 2x2 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, -1),
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Overlay(d.src1, d.src2, d.p, d.a)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 1) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlayCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
a float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"OverlayCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := OverlayCenter(d.src1, d.src2, 0.5)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
261
vendor/github.com/disintegration/imaging/transform_test.go
generated
vendored
Normal file
261
vendor/github.com/disintegration/imaging/transform_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRotate90(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate90 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate90(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate180(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate180 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
|
||||
0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate180(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate270(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate270 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate270(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlipV(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"FlipV 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := FlipV(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlipH(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"FlipH 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
|
||||
0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := FlipH(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Transpose 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Transpose(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransverse(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Transverse 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Transverse(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
81
vendor/github.com/disintegration/imaging/utils_test.go
generated
vendored
Normal file
81
vendor/github.com/disintegration/imaging/utils_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package imaging
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testParallelN(enabled bool, n, procs int) bool {
|
||||
data := make([]bool, n)
|
||||
before := runtime.GOMAXPROCS(0)
|
||||
runtime.GOMAXPROCS(procs)
|
||||
parallel(n, func(start, end int) {
|
||||
for i := start; i < end; i++ {
|
||||
data[i] = true
|
||||
}
|
||||
})
|
||||
for i := 0; i < n; i++ {
|
||||
if data[i] != true {
|
||||
return false
|
||||
}
|
||||
}
|
||||
runtime.GOMAXPROCS(before)
|
||||
return true
|
||||
}
|
||||
|
||||
func TestParallel(t *testing.T) {
|
||||
for _, e := range []bool{true, false} {
|
||||
for _, n := range []int{1, 10, 100, 1000} {
|
||||
for _, p := range []int{1, 2, 4, 8, 16, 100} {
|
||||
if testParallelN(e, n, p) != true {
|
||||
t.Errorf("test [parallel %v %d %d] failed", e, n, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClamp(t *testing.T) {
|
||||
td := []struct {
|
||||
f float64
|
||||
u uint8
|
||||
}{
|
||||
{0, 0},
|
||||
{255, 255},
|
||||
{128, 128},
|
||||
{0.49, 0},
|
||||
{0.50, 1},
|
||||
{254.9, 255},
|
||||
{254.0, 254},
|
||||
{256, 255},
|
||||
{2500, 255},
|
||||
{-10, 0},
|
||||
{127.6, 128},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
if clamp(d.f) != d.u {
|
||||
t.Errorf("test [clamp %v %v] failed: %v", d.f, d.u, clamp(d.f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClampint32(t *testing.T) {
|
||||
td := []struct {
|
||||
i int32
|
||||
u uint8
|
||||
}{
|
||||
{0, 0},
|
||||
{255, 255},
|
||||
{128, 128},
|
||||
{256, 255},
|
||||
{2500, 255},
|
||||
{-10, 0},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
if clampint32(d.i) != d.u {
|
||||
t.Errorf("test [clampint32 %v %v] failed: %v", d.i, d.u, clampint32(d.i))
|
||||
}
|
||||
}
|
||||
}
|
||||
16
vendor/github.com/garyburd/redigo/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/garyburd/redigo/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
language: go
|
||||
sudo: false
|
||||
services:
|
||||
- redis-server
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go get -t -v ./...
|
||||
- diff -u <(echo -n) <(gofmt -d .)
|
||||
- go vet $(go list ./... | grep -v /vendor/)
|
||||
- go test -v -race ./...
|
||||
50
vendor/github.com/garyburd/redigo/README.markdown
generated
vendored
Normal file
50
vendor/github.com/garyburd/redigo/README.markdown
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
Redigo
|
||||
======
|
||||
|
||||
[](https://travis-ci.org/garyburd/redigo)
|
||||
[](https://godoc.org/github.com/garyburd/redigo/redis)
|
||||
|
||||
Redigo is a [Go](http://golang.org/) client for the [Redis](http://redis.io/) database.
|
||||
|
||||
Features
|
||||
-------
|
||||
|
||||
* A [Print-like](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Executing_Commands) API with support for all Redis commands.
|
||||
* [Pipelining](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining), including pipelined transactions.
|
||||
* [Publish/Subscribe](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Publish_and_Subscribe).
|
||||
* [Connection pooling](http://godoc.org/github.com/garyburd/redigo/redis#Pool).
|
||||
* [Script helper type](http://godoc.org/github.com/garyburd/redigo/redis#Script) with optimistic use of EVALSHA.
|
||||
* [Helper functions](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Reply_Helpers) for working with command replies.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
- [API Reference](http://godoc.org/github.com/garyburd/redigo/redis)
|
||||
- [FAQ](https://github.com/garyburd/redigo/wiki/FAQ)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install Redigo using the "go get" command:
|
||||
|
||||
go get github.com/garyburd/redigo/redis
|
||||
|
||||
The Go distribution is Redigo's only dependency.
|
||||
|
||||
Related Projects
|
||||
----------------
|
||||
|
||||
- [rafaeljusto/redigomock](https://godoc.org/github.com/rafaeljusto/redigomock) - A mock library for Redigo.
|
||||
- [chasex/redis-go-cluster](https://github.com/chasex/redis-go-cluster) - A Redis cluster client implementation.
|
||||
- [FZambia/go-sentinel](https://github.com/FZambia/go-sentinel) - Redis Sentinel support for Redigo
|
||||
- [PuerkitoBio/redisc](https://github.com/PuerkitoBio/redisc) - Redis Cluster client built on top of Redigo
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Send email to Gary Burd (address in GitHub profile) before doing any work on Redigo.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Redigo is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||
2
vendor/github.com/garyburd/redigo/internal/commandinfo.go
generated
vendored
2
vendor/github.com/garyburd/redigo/internal/commandinfo.go
generated
vendored
|
|
@ -12,7 +12,7 @@
|
|||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package internal
|
||||
package internal // import "github.com/garyburd/redigo/internal"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
|
|
|||
27
vendor/github.com/garyburd/redigo/internal/commandinfo_test.go
generated
vendored
Normal file
27
vendor/github.com/garyburd/redigo/internal/commandinfo_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package internal
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLookupCommandInfo(t *testing.T) {
|
||||
for _, n := range []string{"watch", "WATCH", "wAtch"} {
|
||||
if LookupCommandInfo(n) == (CommandInfo{}) {
|
||||
t.Errorf("LookupCommandInfo(%q) = CommandInfo{}, expected non-zero value", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkLookupCommandInfo(b *testing.B, names ...string) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, c := range names {
|
||||
LookupCommandInfo(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLookupCommandInfoCorrectCase(b *testing.B) {
|
||||
benchmarkLookupCommandInfo(b, "watch", "WATCH", "monitor", "MONITOR")
|
||||
}
|
||||
|
||||
func BenchmarkLookupCommandInfoMixedCase(b *testing.B) {
|
||||
benchmarkLookupCommandInfo(b, "wAtch", "WeTCH", "monItor", "MONiTOR")
|
||||
}
|
||||
68
vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
generated
vendored
Normal file
68
vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2014 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
// Package redistest contains utilities for writing Redigo tests.
|
||||
package redistest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type testConn struct {
|
||||
redis.Conn
|
||||
}
|
||||
|
||||
func (t testConn) Close() error {
|
||||
_, err := t.Conn.Do("SELECT", "9")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = t.Conn.Do("FLUSHDB")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Conn.Close()
|
||||
}
|
||||
|
||||
// Dial dials the local Redis server and selects database 9. To prevent
|
||||
// stomping on real data, DialTestDB fails if database 9 contains data. The
|
||||
// returned connection flushes database 9 on close.
|
||||
func Dial() (redis.Conn, error) {
|
||||
c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = c.Do("SELECT", "9")
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := redis.Int(c.Do("DBSIZE"))
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n != 0 {
|
||||
c.Close()
|
||||
return nil, errors.New("database #9 is not empty, test can not continue")
|
||||
}
|
||||
|
||||
return testConn{c}, nil
|
||||
}
|
||||
670
vendor/github.com/garyburd/redigo/redis/conn_test.go
generated
vendored
Normal file
670
vendor/github.com/garyburd/redigo/redis/conn_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,670 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type testConn struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (*testConn) Close() error { return nil }
|
||||
func (*testConn) LocalAddr() net.Addr { return nil }
|
||||
func (*testConn) RemoteAddr() net.Addr { return nil }
|
||||
func (*testConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (*testConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (*testConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
func dialTestConn(r io.Reader, w io.Writer) redis.DialOption {
|
||||
return redis.DialNetDial(func(net, addr string) (net.Conn, error) {
|
||||
return &testConn{Reader: r, Writer: w}, nil
|
||||
})
|
||||
}
|
||||
|
||||
var writeTests = []struct {
|
||||
args []interface{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
[]interface{}{"SET", "key", "value"},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", "value"},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", byte(100)},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", 100},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", int64(math.MinInt64)},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$20\r\n-9223372036854775808\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", float64(1349673917.939762)},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$21\r\n1.349673917939762e+09\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", ""},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", nil},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"ECHO", true, false},
|
||||
"*3\r\n$4\r\nECHO\r\n$1\r\n1\r\n$1\r\n0\r\n",
|
||||
},
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
for _, tt := range writeTests {
|
||||
var buf bytes.Buffer
|
||||
c, _ := redis.Dial("", "", dialTestConn(nil, &buf))
|
||||
err := c.Send(tt.args[0].(string), tt.args[1:]...)
|
||||
if err != nil {
|
||||
t.Errorf("Send(%v) returned error %v", tt.args, err)
|
||||
continue
|
||||
}
|
||||
c.Flush()
|
||||
actual := buf.String()
|
||||
if actual != tt.expected {
|
||||
t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var errorSentinel = &struct{}{}
|
||||
|
||||
var readTests = []struct {
|
||||
reply string
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
"+OK\r\n",
|
||||
"OK",
|
||||
},
|
||||
{
|
||||
"+PONG\r\n",
|
||||
"PONG",
|
||||
},
|
||||
{
|
||||
"@OK\r\n",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
"$6\r\nfoobar\r\n",
|
||||
[]byte("foobar"),
|
||||
},
|
||||
{
|
||||
"$-1\r\n",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
":1\r\n",
|
||||
int64(1),
|
||||
},
|
||||
{
|
||||
":-2\r\n",
|
||||
int64(-2),
|
||||
},
|
||||
{
|
||||
"*0\r\n",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
"*-1\r\n",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
|
||||
[]interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
|
||||
},
|
||||
{
|
||||
"*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
|
||||
[]interface{}{[]byte("foo"), nil, []byte("bar")},
|
||||
},
|
||||
|
||||
{
|
||||
// "x" is not a valid length
|
||||
"$x\r\nfoobar\r\n",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
// -2 is not a valid length
|
||||
"$-2\r\n",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
// "x" is not a valid integer
|
||||
":x\r\n",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
// missing \r\n following value
|
||||
"$6\r\nfoobar",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
// short value
|
||||
"$6\r\nxx",
|
||||
errorSentinel,
|
||||
},
|
||||
{
|
||||
// long value
|
||||
"$6\r\nfoobarx\r\n",
|
||||
errorSentinel,
|
||||
},
|
||||
}
|
||||
|
||||
func TestRead(t *testing.T) {
|
||||
for _, tt := range readTests {
|
||||
c, _ := redis.Dial("", "", dialTestConn(strings.NewReader(tt.reply), nil))
|
||||
actual, err := c.Receive()
|
||||
if tt.expected == errorSentinel {
|
||||
if err == nil {
|
||||
t.Errorf("Receive(%q) did not return expected error", tt.reply)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Receive(%q) returned error %v", tt.reply, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(actual, tt.expected) {
|
||||
t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCommands = []struct {
|
||||
args []interface{}
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
[]interface{}{"PING"},
|
||||
"PONG",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "foo", "bar"},
|
||||
"OK",
|
||||
},
|
||||
{
|
||||
[]interface{}{"GET", "foo"},
|
||||
[]byte("bar"),
|
||||
},
|
||||
{
|
||||
[]interface{}{"GET", "nokey"},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]interface{}{"MGET", "nokey", "foo"},
|
||||
[]interface{}{nil, []byte("bar")},
|
||||
},
|
||||
{
|
||||
[]interface{}{"INCR", "mycounter"},
|
||||
int64(1),
|
||||
},
|
||||
{
|
||||
[]interface{}{"LPUSH", "mylist", "foo"},
|
||||
int64(1),
|
||||
},
|
||||
{
|
||||
[]interface{}{"LPUSH", "mylist", "bar"},
|
||||
int64(2),
|
||||
},
|
||||
{
|
||||
[]interface{}{"LRANGE", "mylist", 0, -1},
|
||||
[]interface{}{[]byte("bar"), []byte("foo")},
|
||||
},
|
||||
{
|
||||
[]interface{}{"MULTI"},
|
||||
"OK",
|
||||
},
|
||||
{
|
||||
[]interface{}{"LRANGE", "mylist", 0, -1},
|
||||
"QUEUED",
|
||||
},
|
||||
{
|
||||
[]interface{}{"PING"},
|
||||
"QUEUED",
|
||||
},
|
||||
{
|
||||
[]interface{}{"EXEC"},
|
||||
[]interface{}{
|
||||
[]interface{}{[]byte("bar"), []byte("foo")},
|
||||
"PONG",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestDoCommands(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
for _, cmd := range testCommands {
|
||||
actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
|
||||
if err != nil {
|
||||
t.Errorf("Do(%v) returned error %v", cmd.args, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(actual, cmd.expected) {
|
||||
t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipelineCommands(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
for _, cmd := range testCommands {
|
||||
if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
|
||||
t.Fatalf("Send(%v) returned error %v", cmd.args, err)
|
||||
}
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
t.Errorf("Flush() returned error %v", err)
|
||||
}
|
||||
for _, cmd := range testCommands {
|
||||
actual, err := c.Receive()
|
||||
if err != nil {
|
||||
t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, cmd.expected) {
|
||||
t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlankCommmand(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
for _, cmd := range testCommands {
|
||||
if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
|
||||
t.Fatalf("Send(%v) returned error %v", cmd.args, err)
|
||||
}
|
||||
}
|
||||
reply, err := redis.Values(c.Do(""))
|
||||
if err != nil {
|
||||
t.Fatalf("Do() returned error %v", err)
|
||||
}
|
||||
if len(reply) != len(testCommands) {
|
||||
t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
|
||||
}
|
||||
for i, cmd := range testCommands {
|
||||
actual := reply[i]
|
||||
if !reflect.DeepEqual(actual, cmd.expected) {
|
||||
t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecvBeforeSend(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
c.Receive()
|
||||
close(done)
|
||||
}()
|
||||
time.Sleep(time.Millisecond)
|
||||
c.Send("PING")
|
||||
c.Flush()
|
||||
<-done
|
||||
_, err = c.Do("")
|
||||
if err != nil {
|
||||
t.Fatalf("error=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Do("SET", "key", "val")
|
||||
_, err = c.Do("HSET", "key", "fld", "val")
|
||||
if err == nil {
|
||||
t.Errorf("Expected err for HSET on string key.")
|
||||
}
|
||||
if c.Err() != nil {
|
||||
t.Errorf("Conn has Err()=%v, expect nil", c.Err())
|
||||
}
|
||||
_, err = c.Do("SET", "key", "val")
|
||||
if err != nil {
|
||||
t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadTimeout(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("net.Listen returned %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
c.Write([]byte("+OK\r\n"))
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
// Do
|
||||
|
||||
c1, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatalf("redis.Dial returned %v", err)
|
||||
}
|
||||
defer c1.Close()
|
||||
|
||||
_, err = c1.Do("PING")
|
||||
if err == nil {
|
||||
t.Fatalf("c1.Do() returned nil, expect error")
|
||||
}
|
||||
if c1.Err() == nil {
|
||||
t.Fatalf("c1.Err() = nil, expect error")
|
||||
}
|
||||
|
||||
// Send/Flush/Receive
|
||||
|
||||
c2, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatalf("redis.Dial returned %v", err)
|
||||
}
|
||||
defer c2.Close()
|
||||
|
||||
c2.Send("PING")
|
||||
c2.Flush()
|
||||
_, err = c2.Receive()
|
||||
if err == nil {
|
||||
t.Fatalf("c2.Receive() returned nil, expect error")
|
||||
}
|
||||
if c2.Err() == nil {
|
||||
t.Fatalf("c2.Err() = nil, expect error")
|
||||
}
|
||||
}
|
||||
|
||||
var dialErrors = []struct {
|
||||
rawurl string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
"localhost",
|
||||
"invalid redis URL scheme",
|
||||
},
|
||||
// The error message for invalid hosts is diffferent in different
|
||||
// versions of Go, so just check that there is an error message.
|
||||
{
|
||||
"redis://weird url",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"redis://foo:bar:baz",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"http://www.google.com",
|
||||
"invalid redis URL scheme: http",
|
||||
},
|
||||
{
|
||||
"redis://localhost:6379/abc123",
|
||||
"invalid database: abc123",
|
||||
},
|
||||
}
|
||||
|
||||
func TestDialURLErrors(t *testing.T) {
|
||||
for _, d := range dialErrors {
|
||||
_, err := redis.DialURL(d.rawurl)
|
||||
if err == nil || !strings.Contains(err.Error(), d.expectedError) {
|
||||
t.Errorf("DialURL did not return expected error (expected %v to contain %s)", err, d.expectedError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialURLPort(t *testing.T) {
|
||||
checkPort := func(network, address string) (net.Conn, error) {
|
||||
if address != "localhost:6379" {
|
||||
t.Errorf("DialURL did not set port to 6379 by default (got %v)", address)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := redis.DialURL("redis://localhost", redis.DialNetDial(checkPort))
|
||||
if err != nil {
|
||||
t.Error("dial error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialURLHost(t *testing.T) {
|
||||
checkHost := func(network, address string) (net.Conn, error) {
|
||||
if address != "localhost:6379" {
|
||||
t.Errorf("DialURL did not set host to localhost by default (got %v)", address)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := redis.DialURL("redis://:6379", redis.DialNetDial(checkHost))
|
||||
if err != nil {
|
||||
t.Error("dial error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialURLPassword(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
_, err := redis.DialURL("redis://x:abc123@localhost", dialTestConn(strings.NewReader("+OK\r\n"), &buf))
|
||||
if err != nil {
|
||||
t.Error("dial error:", err)
|
||||
}
|
||||
expected := "*2\r\n$4\r\nAUTH\r\n$6\r\nabc123\r\n"
|
||||
actual := buf.String()
|
||||
if actual != expected {
|
||||
t.Errorf("commands = %q, want %q", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialURLDatabase(t *testing.T) {
|
||||
var buf3 bytes.Buffer
|
||||
_, err3 := redis.DialURL("redis://localhost/3", dialTestConn(strings.NewReader("+OK\r\n"), &buf3))
|
||||
if err3 != nil {
|
||||
t.Error("dial error:", err3)
|
||||
}
|
||||
expected3 := "*2\r\n$6\r\nSELECT\r\n$1\r\n3\r\n"
|
||||
actual3 := buf3.String()
|
||||
if actual3 != expected3 {
|
||||
t.Errorf("commands = %q, want %q", actual3, expected3)
|
||||
}
|
||||
// empty DB means 0
|
||||
var buf0 bytes.Buffer
|
||||
_, err0 := redis.DialURL("redis://localhost/", dialTestConn(strings.NewReader("+OK\r\n"), &buf0))
|
||||
if err0 != nil {
|
||||
t.Error("dial error:", err0)
|
||||
}
|
||||
expected0 := ""
|
||||
actual0 := buf0.String()
|
||||
if actual0 != expected0 {
|
||||
t.Errorf("commands = %q, want %q", actual0, expected0)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to local instance of Redis running on the default port.
|
||||
func ExampleDial() {
|
||||
c, err := redis.Dial("tcp", ":6379")
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
defer c.Close()
|
||||
}
|
||||
|
||||
// Connect to remote instance of Redis using a URL.
|
||||
func ExampleDialURL() {
|
||||
c, err := redis.DialURL(os.Getenv("REDIS_URL"))
|
||||
if err != nil {
|
||||
// handle connection error
|
||||
}
|
||||
defer c.Close()
|
||||
}
|
||||
|
||||
// TextExecError tests handling of errors in a transaction. See
|
||||
// http://redis.io/topics/transactions for information on how Redis handles
|
||||
// errors in a transaction.
|
||||
func TestExecError(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
// Execute commands that fail before EXEC is called.
|
||||
|
||||
c.Do("DEL", "k0")
|
||||
c.Do("ZADD", "k0", 0, 0)
|
||||
c.Send("MULTI")
|
||||
c.Send("NOTACOMMAND", "k0", 0, 0)
|
||||
c.Send("ZINCRBY", "k0", 0, 0)
|
||||
v, err := c.Do("EXEC")
|
||||
if err == nil {
|
||||
t.Fatalf("EXEC returned values %v, expected error", v)
|
||||
}
|
||||
|
||||
// Execute commands that fail after EXEC is called. The first command
|
||||
// returns an error.
|
||||
|
||||
c.Do("DEL", "k1")
|
||||
c.Do("ZADD", "k1", 0, 0)
|
||||
c.Send("MULTI")
|
||||
c.Send("HSET", "k1", 0, 0)
|
||||
c.Send("ZINCRBY", "k1", 0, 0)
|
||||
v, err = c.Do("EXEC")
|
||||
if err != nil {
|
||||
t.Fatalf("EXEC returned error %v", err)
|
||||
}
|
||||
|
||||
vs, err := redis.Values(v, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Values(v) returned error %v", err)
|
||||
}
|
||||
|
||||
if len(vs) != 2 {
|
||||
t.Fatalf("len(vs) == %d, want 2", len(vs))
|
||||
}
|
||||
|
||||
if _, ok := vs[0].(error); !ok {
|
||||
t.Fatalf("first result is type %T, expected error", vs[0])
|
||||
}
|
||||
|
||||
if _, ok := vs[1].([]byte); !ok {
|
||||
t.Fatalf("second result is type %T, expected []byte", vs[1])
|
||||
}
|
||||
|
||||
// Execute commands that fail after EXEC is called. The second command
|
||||
// returns an error.
|
||||
|
||||
c.Do("ZADD", "k2", 0, 0)
|
||||
c.Send("MULTI")
|
||||
c.Send("ZINCRBY", "k2", 0, 0)
|
||||
c.Send("HSET", "k2", 0, 0)
|
||||
v, err = c.Do("EXEC")
|
||||
if err != nil {
|
||||
t.Fatalf("EXEC returned error %v", err)
|
||||
}
|
||||
|
||||
vs, err = redis.Values(v, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Values(v) returned error %v", err)
|
||||
}
|
||||
|
||||
if len(vs) != 2 {
|
||||
t.Fatalf("len(vs) == %d, want 2", len(vs))
|
||||
}
|
||||
|
||||
if _, ok := vs[0].([]byte); !ok {
|
||||
t.Fatalf("first result is type %T, expected []byte", vs[0])
|
||||
}
|
||||
|
||||
if _, ok := vs[1].(error); !ok {
|
||||
t.Fatalf("second result is type %T, expected error", vs[2])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDoEmpty(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := c.Do(""); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDoPing(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/garyburd/redigo/redis/doc.go
generated
vendored
2
vendor/github.com/garyburd/redigo/redis/doc.go
generated
vendored
|
|
@ -166,4 +166,4 @@
|
|||
// if _, err := redis.Scan(reply, &value1, &value2); err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
package redis
|
||||
package redis // import "github.com/garyburd/redigo/redis"
|
||||
|
|
|
|||
684
vendor/github.com/garyburd/redigo/redis/pool_test.go
generated
vendored
Normal file
684
vendor/github.com/garyburd/redigo/redis/pool_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
// Copyright 2011 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type poolTestConn struct {
|
||||
d *poolDialer
|
||||
err error
|
||||
redis.Conn
|
||||
}
|
||||
|
||||
func (c *poolTestConn) Close() error {
|
||||
c.d.mu.Lock()
|
||||
c.d.open -= 1
|
||||
c.d.mu.Unlock()
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (c *poolTestConn) Err() error { return c.err }
|
||||
|
||||
func (c *poolTestConn) Do(commandName string, args ...interface{}) (interface{}, error) {
|
||||
if commandName == "ERR" {
|
||||
c.err = args[0].(error)
|
||||
commandName = "PING"
|
||||
}
|
||||
if commandName != "" {
|
||||
c.d.commands = append(c.d.commands, commandName)
|
||||
}
|
||||
return c.Conn.Do(commandName, args...)
|
||||
}
|
||||
|
||||
func (c *poolTestConn) Send(commandName string, args ...interface{}) error {
|
||||
c.d.commands = append(c.d.commands, commandName)
|
||||
return c.Conn.Send(commandName, args...)
|
||||
}
|
||||
|
||||
type poolDialer struct {
|
||||
mu sync.Mutex
|
||||
t *testing.T
|
||||
dialed int
|
||||
open int
|
||||
commands []string
|
||||
dialErr error
|
||||
}
|
||||
|
||||
func (d *poolDialer) dial() (redis.Conn, error) {
|
||||
d.mu.Lock()
|
||||
d.dialed += 1
|
||||
dialErr := d.dialErr
|
||||
d.mu.Unlock()
|
||||
if dialErr != nil {
|
||||
return nil, d.dialErr
|
||||
}
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.mu.Lock()
|
||||
d.open += 1
|
||||
d.mu.Unlock()
|
||||
return &poolTestConn{d: d, Conn: c}, nil
|
||||
}
|
||||
|
||||
func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
|
||||
d.mu.Lock()
|
||||
if d.dialed != dialed {
|
||||
d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
|
||||
}
|
||||
if d.open != open {
|
||||
d.t.Errorf("%s: open=%d, want %d", message, d.open, open)
|
||||
}
|
||||
if active := p.ActiveCount(); active != open {
|
||||
d.t.Errorf("%s: active=%d, want %d", message, active, open)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
func TestPoolReuse(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
c1 := p.Get()
|
||||
c1.Do("PING")
|
||||
c2 := p.Get()
|
||||
c2.Do("PING")
|
||||
c1.Close()
|
||||
c2.Close()
|
||||
}
|
||||
|
||||
d.check("before close", p, 2, 2)
|
||||
p.Close()
|
||||
d.check("after close", p, 2, 0)
|
||||
}
|
||||
|
||||
func TestPoolMaxIdle(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
c1 := p.Get()
|
||||
c1.Do("PING")
|
||||
c2 := p.Get()
|
||||
c2.Do("PING")
|
||||
c3 := p.Get()
|
||||
c3.Do("PING")
|
||||
c1.Close()
|
||||
c2.Close()
|
||||
c3.Close()
|
||||
}
|
||||
d.check("before close", p, 12, 2)
|
||||
p.Close()
|
||||
d.check("after close", p, 12, 0)
|
||||
}
|
||||
|
||||
func TestPoolError(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
c.Do("ERR", io.EOF)
|
||||
if c.Err() == nil {
|
||||
t.Errorf("expected c.Err() != nil")
|
||||
}
|
||||
c.Close()
|
||||
|
||||
c = p.Get()
|
||||
c.Do("ERR", io.EOF)
|
||||
c.Close()
|
||||
|
||||
d.check(".", p, 2, 0)
|
||||
}
|
||||
|
||||
func TestPoolClose(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c1 := p.Get()
|
||||
c1.Do("PING")
|
||||
c2 := p.Get()
|
||||
c2.Do("PING")
|
||||
c3 := p.Get()
|
||||
c3.Do("PING")
|
||||
|
||||
c1.Close()
|
||||
if _, err := c1.Do("PING"); err == nil {
|
||||
t.Errorf("expected error after connection closed")
|
||||
}
|
||||
|
||||
c2.Close()
|
||||
c2.Close()
|
||||
|
||||
p.Close()
|
||||
|
||||
d.check("after pool close", p, 3, 1)
|
||||
|
||||
if _, err := c1.Do("PING"); err == nil {
|
||||
t.Errorf("expected error after connection and pool closed")
|
||||
}
|
||||
|
||||
c3.Close()
|
||||
|
||||
d.check("after conn close", p, 3, 0)
|
||||
|
||||
c1 = p.Get()
|
||||
if _, err := c1.Do("PING"); err == nil {
|
||||
t.Errorf("expected error after pool closed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoolTimeout(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
IdleTimeout: 300 * time.Second,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
now := time.Now()
|
||||
redis.SetNowFunc(func() time.Time { return now })
|
||||
defer redis.SetNowFunc(time.Now)
|
||||
|
||||
c := p.Get()
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
d.check("1", p, 1, 1)
|
||||
|
||||
now = now.Add(p.IdleTimeout)
|
||||
|
||||
c = p.Get()
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
d.check("2", p, 2, 1)
|
||||
}
|
||||
|
||||
func TestPoolConcurrenSendReceive(t *testing.T) {
|
||||
p := &redis.Pool{
|
||||
Dial: redis.DialDefaultServer,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := c.Receive()
|
||||
done <- err
|
||||
}()
|
||||
c.Send("PING")
|
||||
c.Flush()
|
||||
err := <-done
|
||||
if err != nil {
|
||||
t.Fatalf("Receive() returned error %v", err)
|
||||
}
|
||||
_, err = c.Do("")
|
||||
if err != nil {
|
||||
t.Fatalf("Do() returned error %v", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestPoolBorrowCheck(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
Dial: d.dial,
|
||||
TestOnBorrow: func(redis.Conn, time.Time) error { return redis.Error("BLAH") },
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
c := p.Get()
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
}
|
||||
d.check("1", p, 10, 1)
|
||||
}
|
||||
|
||||
func TestPoolMaxActive(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
MaxActive: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c1 := p.Get()
|
||||
c1.Do("PING")
|
||||
c2 := p.Get()
|
||||
c2.Do("PING")
|
||||
|
||||
d.check("1", p, 2, 2)
|
||||
|
||||
c3 := p.Get()
|
||||
if _, err := c3.Do("PING"); err != redis.ErrPoolExhausted {
|
||||
t.Errorf("expected pool exhausted")
|
||||
}
|
||||
|
||||
c3.Close()
|
||||
d.check("2", p, 2, 2)
|
||||
c2.Close()
|
||||
d.check("3", p, 2, 2)
|
||||
|
||||
c3 = p.Get()
|
||||
if _, err := c3.Do("PING"); err != nil {
|
||||
t.Errorf("expected good channel, err=%v", err)
|
||||
}
|
||||
c3.Close()
|
||||
|
||||
d.check("4", p, 2, 2)
|
||||
}
|
||||
|
||||
func TestPoolMonitorCleanup(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
MaxActive: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
c.Send("MONITOR")
|
||||
c.Close()
|
||||
|
||||
d.check("", p, 1, 0)
|
||||
}
|
||||
|
||||
func TestPoolPubSubCleanup(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
MaxActive: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
c.Send("SUBSCRIBE", "x")
|
||||
c.Close()
|
||||
|
||||
want := []string{"SUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
|
||||
c = p.Get()
|
||||
c.Send("PSUBSCRIBE", "x*")
|
||||
c.Close()
|
||||
|
||||
want = []string{"PSUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
}
|
||||
|
||||
func TestPoolTransactionCleanup(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 2,
|
||||
MaxActive: 2,
|
||||
Dial: d.dial,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
c.Do("WATCH", "key")
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
want := []string{"WATCH", "PING", "UNWATCH"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
|
||||
c = p.Get()
|
||||
c.Do("WATCH", "key")
|
||||
c.Do("UNWATCH")
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
want = []string{"WATCH", "UNWATCH", "PING"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
|
||||
c = p.Get()
|
||||
c.Do("WATCH", "key")
|
||||
c.Do("MULTI")
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
want = []string{"WATCH", "MULTI", "PING", "DISCARD"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
|
||||
c = p.Get()
|
||||
c.Do("WATCH", "key")
|
||||
c.Do("MULTI")
|
||||
c.Do("DISCARD")
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
want = []string{"WATCH", "MULTI", "DISCARD", "PING"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
|
||||
c = p.Get()
|
||||
c.Do("WATCH", "key")
|
||||
c.Do("MULTI")
|
||||
c.Do("EXEC")
|
||||
c.Do("PING")
|
||||
c.Close()
|
||||
|
||||
want = []string{"WATCH", "MULTI", "EXEC", "PING"}
|
||||
if !reflect.DeepEqual(d.commands, want) {
|
||||
t.Errorf("got commands %v, want %v", d.commands, want)
|
||||
}
|
||||
d.commands = nil
|
||||
}
|
||||
|
||||
func startGoroutines(p *redis.Pool, cmd string, args ...interface{}) chan error {
|
||||
errs := make(chan error, 10)
|
||||
for i := 0; i < cap(errs); i++ {
|
||||
go func() {
|
||||
c := p.Get()
|
||||
_, err := c.Do(cmd, args...)
|
||||
errs <- err
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for goroutines to block.
|
||||
time.Sleep(time.Second / 4)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func TestWaitPool(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 1,
|
||||
MaxActive: 1,
|
||||
Dial: d.dial,
|
||||
Wait: true,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
errs := startGoroutines(p, "PING")
|
||||
d.check("before close", p, 1, 1)
|
||||
c.Close()
|
||||
timeout := time.After(2 * time.Second)
|
||||
for i := 0; i < cap(errs); i++ {
|
||||
select {
|
||||
case err := <-errs:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatalf("timeout waiting for blocked goroutine %d", i)
|
||||
}
|
||||
}
|
||||
d.check("done", p, 1, 1)
|
||||
}
|
||||
|
||||
func TestWaitPoolClose(t *testing.T) {
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 1,
|
||||
MaxActive: 1,
|
||||
Dial: d.dial,
|
||||
Wait: true,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
errs := startGoroutines(p, "PING")
|
||||
d.check("before close", p, 1, 1)
|
||||
p.Close()
|
||||
timeout := time.After(2 * time.Second)
|
||||
for i := 0; i < cap(errs); i++ {
|
||||
select {
|
||||
case err := <-errs:
|
||||
switch err {
|
||||
case nil:
|
||||
t.Fatal("blocked goroutine did not get error")
|
||||
case redis.ErrPoolExhausted:
|
||||
t.Fatal("blocked goroutine got pool exhausted error")
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatal("timeout waiting for blocked goroutine")
|
||||
}
|
||||
}
|
||||
c.Close()
|
||||
d.check("done", p, 1, 0)
|
||||
}
|
||||
|
||||
func TestWaitPoolCommandError(t *testing.T) {
|
||||
testErr := errors.New("test")
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 1,
|
||||
MaxActive: 1,
|
||||
Dial: d.dial,
|
||||
Wait: true,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
errs := startGoroutines(p, "ERR", testErr)
|
||||
d.check("before close", p, 1, 1)
|
||||
c.Close()
|
||||
timeout := time.After(2 * time.Second)
|
||||
for i := 0; i < cap(errs); i++ {
|
||||
select {
|
||||
case err := <-errs:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatalf("timeout waiting for blocked goroutine %d", i)
|
||||
}
|
||||
}
|
||||
d.check("done", p, cap(errs), 0)
|
||||
}
|
||||
|
||||
func TestWaitPoolDialError(t *testing.T) {
|
||||
testErr := errors.New("test")
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: 1,
|
||||
MaxActive: 1,
|
||||
Dial: d.dial,
|
||||
Wait: true,
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
c := p.Get()
|
||||
errs := startGoroutines(p, "ERR", testErr)
|
||||
d.check("before close", p, 1, 1)
|
||||
|
||||
d.dialErr = errors.New("dial")
|
||||
c.Close()
|
||||
|
||||
nilCount := 0
|
||||
errCount := 0
|
||||
timeout := time.After(2 * time.Second)
|
||||
for i := 0; i < cap(errs); i++ {
|
||||
select {
|
||||
case err := <-errs:
|
||||
switch err {
|
||||
case nil:
|
||||
nilCount++
|
||||
case d.dialErr:
|
||||
errCount++
|
||||
default:
|
||||
t.Fatalf("expected dial error or nil, got %v", err)
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatalf("timeout waiting for blocked goroutine %d", i)
|
||||
}
|
||||
}
|
||||
if nilCount != 1 {
|
||||
t.Errorf("expected one nil error, got %d", nilCount)
|
||||
}
|
||||
if errCount != cap(errs)-1 {
|
||||
t.Errorf("expected %d dial erors, got %d", cap(errs)-1, errCount)
|
||||
}
|
||||
d.check("done", p, cap(errs), 0)
|
||||
}
|
||||
|
||||
// Borrowing requires us to iterate over the idle connections, unlock the pool,
|
||||
// and perform a blocking operation to check the connection still works. If
|
||||
// TestOnBorrow fails, we must reacquire the lock and continue iteration. This
|
||||
// test ensures that iteration will work correctly if multiple threads are
|
||||
// iterating simultaneously.
|
||||
func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
|
||||
const count = 100
|
||||
|
||||
// First we'll Create a pool where the pilfering of idle connections fails.
|
||||
d := poolDialer{t: t}
|
||||
p := &redis.Pool{
|
||||
MaxIdle: count,
|
||||
MaxActive: count,
|
||||
Dial: d.dial,
|
||||
TestOnBorrow: func(c redis.Conn, t time.Time) error {
|
||||
return errors.New("No way back into the real world.")
|
||||
},
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
// Fill the pool with idle connections.
|
||||
conns := make([]redis.Conn, count)
|
||||
for i := range conns {
|
||||
conns[i] = p.Get()
|
||||
}
|
||||
for i := range conns {
|
||||
conns[i].Close()
|
||||
}
|
||||
|
||||
// Spawn a bunch of goroutines to thrash the pool.
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(count)
|
||||
for i := 0; i < count; i++ {
|
||||
go func() {
|
||||
c := p.Get()
|
||||
if c.Err() != nil {
|
||||
t.Errorf("pool get failed: %v", c.Err())
|
||||
}
|
||||
c.Close()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
if d.dialed != count*2 {
|
||||
t.Errorf("Expected %d dials, got %d", count*2, d.dialed)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPoolGet(b *testing.B) {
|
||||
b.StopTimer()
|
||||
p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
|
||||
c := p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
defer p.Close()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c = p.Get()
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPoolGetErr(b *testing.B) {
|
||||
b.StopTimer()
|
||||
p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
|
||||
c := p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
defer p.Close()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c = p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPoolGetPing(b *testing.B) {
|
||||
b.StopTimer()
|
||||
p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
|
||||
c := p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
defer p.Close()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c = p.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
148
vendor/github.com/garyburd/redigo/redis/pubsub_test.go
generated
vendored
Normal file
148
vendor/github.com/garyburd/redigo/redis/pubsub_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
func publish(channel, value interface{}) {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
c.Do("PUBLISH", channel, value)
|
||||
}
|
||||
|
||||
// Applications can receive pushed messages from one goroutine and manage subscriptions from another goroutine.
|
||||
func ExamplePubSubConn() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
psc := redis.PubSubConn{Conn: c}
|
||||
|
||||
// This goroutine receives and prints pushed notifications from the server.
|
||||
// The goroutine exits when the connection is unsubscribed from all
|
||||
// channels or there is an error.
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
switch n := psc.Receive().(type) {
|
||||
case redis.Message:
|
||||
fmt.Printf("Message: %s %s\n", n.Channel, n.Data)
|
||||
case redis.PMessage:
|
||||
fmt.Printf("PMessage: %s %s %s\n", n.Pattern, n.Channel, n.Data)
|
||||
case redis.Subscription:
|
||||
fmt.Printf("Subscription: %s %s %d\n", n.Kind, n.Channel, n.Count)
|
||||
if n.Count == 0 {
|
||||
return
|
||||
}
|
||||
case error:
|
||||
fmt.Printf("error: %v\n", n)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// This goroutine manages subscriptions for the connection.
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
psc.Subscribe("example")
|
||||
psc.PSubscribe("p*")
|
||||
|
||||
// The following function calls publish a message using another
|
||||
// connection to the Redis server.
|
||||
publish("example", "hello")
|
||||
publish("example", "world")
|
||||
publish("pexample", "foo")
|
||||
publish("pexample", "bar")
|
||||
|
||||
// Unsubscribe from all connections. This will cause the receiving
|
||||
// goroutine to exit.
|
||||
psc.Unsubscribe()
|
||||
psc.PUnsubscribe()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// Output:
|
||||
// Subscription: subscribe example 1
|
||||
// Subscription: psubscribe p* 2
|
||||
// Message: example hello
|
||||
// Message: example world
|
||||
// PMessage: p* pexample foo
|
||||
// PMessage: p* pexample bar
|
||||
// Subscription: unsubscribe example 1
|
||||
// Subscription: punsubscribe p* 0
|
||||
}
|
||||
|
||||
func expectPushed(t *testing.T, c redis.PubSubConn, message string, expected interface{}) {
|
||||
actual := c.Receive()
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("%s = %v, want %v", message, actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushed(t *testing.T) {
|
||||
pc, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer pc.Close()
|
||||
|
||||
sc, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer sc.Close()
|
||||
|
||||
c := redis.PubSubConn{Conn: sc}
|
||||
|
||||
c.Subscribe("c1")
|
||||
expectPushed(t, c, "Subscribe(c1)", redis.Subscription{Kind: "subscribe", Channel: "c1", Count: 1})
|
||||
c.Subscribe("c2")
|
||||
expectPushed(t, c, "Subscribe(c2)", redis.Subscription{Kind: "subscribe", Channel: "c2", Count: 2})
|
||||
c.PSubscribe("p1")
|
||||
expectPushed(t, c, "PSubscribe(p1)", redis.Subscription{Kind: "psubscribe", Channel: "p1", Count: 3})
|
||||
c.PSubscribe("p2")
|
||||
expectPushed(t, c, "PSubscribe(p2)", redis.Subscription{Kind: "psubscribe", Channel: "p2", Count: 4})
|
||||
c.PUnsubscribe()
|
||||
expectPushed(t, c, "Punsubscribe(p1)", redis.Subscription{Kind: "punsubscribe", Channel: "p1", Count: 3})
|
||||
expectPushed(t, c, "Punsubscribe()", redis.Subscription{Kind: "punsubscribe", Channel: "p2", Count: 2})
|
||||
|
||||
pc.Do("PUBLISH", "c1", "hello")
|
||||
expectPushed(t, c, "PUBLISH c1 hello", redis.Message{Channel: "c1", Data: []byte("hello")})
|
||||
|
||||
c.Ping("hello")
|
||||
expectPushed(t, c, `Ping("hello")`, redis.Pong{Data: "hello"})
|
||||
|
||||
c.Conn.Send("PING")
|
||||
c.Conn.Flush()
|
||||
expectPushed(t, c, `Send("PING")`, redis.Pong{})
|
||||
}
|
||||
179
vendor/github.com/garyburd/redigo/redis/reply_test.go
generated
vendored
Normal file
179
vendor/github.com/garyburd/redigo/redis/reply_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type valueError struct {
|
||||
v interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
func ve(v interface{}, err error) valueError {
|
||||
return valueError{v, err}
|
||||
}
|
||||
|
||||
var replyTests = []struct {
|
||||
name interface{}
|
||||
actual valueError
|
||||
expected valueError
|
||||
}{
|
||||
{
|
||||
"ints([v1, v2])",
|
||||
ve(redis.Ints([]interface{}{[]byte("4"), []byte("5")}, nil)),
|
||||
ve([]int{4, 5}, nil),
|
||||
},
|
||||
{
|
||||
"ints(nil)",
|
||||
ve(redis.Ints(nil, nil)),
|
||||
ve([]int(nil), redis.ErrNil),
|
||||
},
|
||||
{
|
||||
"strings([v1, v2])",
|
||||
ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
|
||||
ve([]string{"v1", "v2"}, nil),
|
||||
},
|
||||
{
|
||||
"strings(nil)",
|
||||
ve(redis.Strings(nil, nil)),
|
||||
ve([]string(nil), redis.ErrNil),
|
||||
},
|
||||
{
|
||||
"byteslices([v1, v2])",
|
||||
ve(redis.ByteSlices([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
|
||||
ve([][]byte{[]byte("v1"), []byte("v2")}, nil),
|
||||
},
|
||||
{
|
||||
"byteslices(nil)",
|
||||
ve(redis.ByteSlices(nil, nil)),
|
||||
ve([][]byte(nil), redis.ErrNil),
|
||||
},
|
||||
{
|
||||
"values([v1, v2])",
|
||||
ve(redis.Values([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
|
||||
ve([]interface{}{[]byte("v1"), []byte("v2")}, nil),
|
||||
},
|
||||
{
|
||||
"values(nil)",
|
||||
ve(redis.Values(nil, nil)),
|
||||
ve([]interface{}(nil), redis.ErrNil),
|
||||
},
|
||||
{
|
||||
"float64(1.0)",
|
||||
ve(redis.Float64([]byte("1.0"), nil)),
|
||||
ve(float64(1.0), nil),
|
||||
},
|
||||
{
|
||||
"float64(nil)",
|
||||
ve(redis.Float64(nil, nil)),
|
||||
ve(float64(0.0), redis.ErrNil),
|
||||
},
|
||||
{
|
||||
"uint64(1)",
|
||||
ve(redis.Uint64(int64(1), nil)),
|
||||
ve(uint64(1), nil),
|
||||
},
|
||||
{
|
||||
"uint64(-1)",
|
||||
ve(redis.Uint64(int64(-1), nil)),
|
||||
ve(uint64(0), redis.ErrNegativeInt),
|
||||
},
|
||||
}
|
||||
|
||||
func TestReply(t *testing.T) {
|
||||
for _, rt := range replyTests {
|
||||
if rt.actual.err != rt.expected.err {
|
||||
t.Errorf("%s returned err %v, want %v", rt.name, rt.actual.err, rt.expected.err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(rt.actual.v, rt.expected.v) {
|
||||
t.Errorf("%s=%+v, want %+v", rt.name, rt.actual.v, rt.expected.v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dial wraps DialDefaultServer() with a more suitable function name for examples.
|
||||
func dial() (redis.Conn, error) {
|
||||
return redis.DialDefaultServer()
|
||||
}
|
||||
|
||||
func ExampleBool() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Do("SET", "foo", 1)
|
||||
exists, _ := redis.Bool(c.Do("EXISTS", "foo"))
|
||||
fmt.Printf("%#v\n", exists)
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleInt() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Do("SET", "k1", 1)
|
||||
n, _ := redis.Int(c.Do("GET", "k1"))
|
||||
fmt.Printf("%#v\n", n)
|
||||
n, _ = redis.Int(c.Do("INCR", "k1"))
|
||||
fmt.Printf("%#v\n", n)
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleInts() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Do("SADD", "set_with_integers", 4, 5, 6)
|
||||
ints, _ := redis.Ints(c.Do("SMEMBERS", "set_with_integers"))
|
||||
fmt.Printf("%#v\n", ints)
|
||||
// Output:
|
||||
// []int{4, 5, 6}
|
||||
}
|
||||
|
||||
func ExampleString() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Do("SET", "hello", "world")
|
||||
s, err := redis.String(c.Do("GET", "hello"))
|
||||
fmt.Printf("%#v\n", s)
|
||||
// Output:
|
||||
// "world"
|
||||
}
|
||||
440
vendor/github.com/garyburd/redigo/redis/scan_test.go
generated
vendored
Normal file
440
vendor/github.com/garyburd/redigo/redis/scan_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
var scanConversionTests = []struct {
|
||||
src interface{}
|
||||
dest interface{}
|
||||
}{
|
||||
{[]byte("-inf"), math.Inf(-1)},
|
||||
{[]byte("+inf"), math.Inf(1)},
|
||||
{[]byte("0"), float64(0)},
|
||||
{[]byte("3.14159"), float64(3.14159)},
|
||||
{[]byte("3.14"), float32(3.14)},
|
||||
{[]byte("-100"), int(-100)},
|
||||
{[]byte("101"), int(101)},
|
||||
{int64(102), int(102)},
|
||||
{[]byte("103"), uint(103)},
|
||||
{int64(104), uint(104)},
|
||||
{[]byte("105"), int8(105)},
|
||||
{int64(106), int8(106)},
|
||||
{[]byte("107"), uint8(107)},
|
||||
{int64(108), uint8(108)},
|
||||
{[]byte("0"), false},
|
||||
{int64(0), false},
|
||||
{[]byte("f"), false},
|
||||
{[]byte("1"), true},
|
||||
{int64(1), true},
|
||||
{[]byte("t"), true},
|
||||
{"hello", "hello"},
|
||||
{[]byte("hello"), "hello"},
|
||||
{[]byte("world"), []byte("world")},
|
||||
{[]interface{}{[]byte("foo")}, []interface{}{[]byte("foo")}},
|
||||
{[]interface{}{[]byte("foo")}, []string{"foo"}},
|
||||
{[]interface{}{[]byte("hello"), []byte("world")}, []string{"hello", "world"}},
|
||||
{[]interface{}{[]byte("bar")}, [][]byte{[]byte("bar")}},
|
||||
{[]interface{}{[]byte("1")}, []int{1}},
|
||||
{[]interface{}{[]byte("1"), []byte("2")}, []int{1, 2}},
|
||||
{[]interface{}{[]byte("1"), []byte("2")}, []float64{1, 2}},
|
||||
{[]interface{}{[]byte("1")}, []byte{1}},
|
||||
{[]interface{}{[]byte("1")}, []bool{true}},
|
||||
}
|
||||
|
||||
func TestScanConversion(t *testing.T) {
|
||||
for _, tt := range scanConversionTests {
|
||||
values := []interface{}{tt.src}
|
||||
dest := reflect.New(reflect.TypeOf(tt.dest))
|
||||
values, err := redis.Scan(values, dest.Interface())
|
||||
if err != nil {
|
||||
t.Errorf("Scan(%v) returned error %v", tt, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(tt.dest, dest.Elem().Interface()) {
|
||||
t.Errorf("Scan(%v) returned %v, want %v", tt, dest.Elem().Interface(), tt.dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var scanConversionErrorTests = []struct {
|
||||
src interface{}
|
||||
dest interface{}
|
||||
}{
|
||||
{[]byte("1234"), byte(0)},
|
||||
{int64(1234), byte(0)},
|
||||
{[]byte("-1"), byte(0)},
|
||||
{int64(-1), byte(0)},
|
||||
{[]byte("junk"), false},
|
||||
{redis.Error("blah"), false},
|
||||
}
|
||||
|
||||
func TestScanConversionError(t *testing.T) {
|
||||
for _, tt := range scanConversionErrorTests {
|
||||
values := []interface{}{tt.src}
|
||||
dest := reflect.New(reflect.TypeOf(tt.dest))
|
||||
values, err := redis.Scan(values, dest.Interface())
|
||||
if err == nil {
|
||||
t.Errorf("Scan(%v) did not return error", tt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleScan() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
|
||||
c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
|
||||
c.Send("HMSET", "album:3", "title", "Beat")
|
||||
c.Send("LPUSH", "albums", "1")
|
||||
c.Send("LPUSH", "albums", "2")
|
||||
c.Send("LPUSH", "albums", "3")
|
||||
values, err := redis.Values(c.Do("SORT", "albums",
|
||||
"BY", "album:*->rating",
|
||||
"GET", "album:*->title",
|
||||
"GET", "album:*->rating"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for len(values) > 0 {
|
||||
var title string
|
||||
rating := -1 // initialize to illegal value to detect nil.
|
||||
values, err = redis.Scan(values, &title, &rating)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if rating == -1 {
|
||||
fmt.Println(title, "not-rated")
|
||||
} else {
|
||||
fmt.Println(title, rating)
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// Beat not-rated
|
||||
// Earthbound 1
|
||||
// Red 5
|
||||
}
|
||||
|
||||
type s0 struct {
|
||||
X int
|
||||
Y int `redis:"y"`
|
||||
Bt bool
|
||||
}
|
||||
|
||||
type s1 struct {
|
||||
X int `redis:"-"`
|
||||
I int `redis:"i"`
|
||||
U uint `redis:"u"`
|
||||
S string `redis:"s"`
|
||||
P []byte `redis:"p"`
|
||||
B bool `redis:"b"`
|
||||
Bt bool
|
||||
Bf bool
|
||||
s0
|
||||
}
|
||||
|
||||
var scanStructTests = []struct {
|
||||
title string
|
||||
reply []string
|
||||
value interface{}
|
||||
}{
|
||||
{"basic",
|
||||
[]string{"i", "-1234", "u", "5678", "s", "hello", "p", "world", "b", "t", "Bt", "1", "Bf", "0", "X", "123", "y", "456"},
|
||||
&s1{I: -1234, U: 5678, S: "hello", P: []byte("world"), B: true, Bt: true, Bf: false, s0: s0{X: 123, Y: 456}},
|
||||
},
|
||||
}
|
||||
|
||||
func TestScanStruct(t *testing.T) {
|
||||
for _, tt := range scanStructTests {
|
||||
|
||||
var reply []interface{}
|
||||
for _, v := range tt.reply {
|
||||
reply = append(reply, []byte(v))
|
||||
}
|
||||
|
||||
value := reflect.New(reflect.ValueOf(tt.value).Type().Elem())
|
||||
|
||||
if err := redis.ScanStruct(reply, value.Interface()); err != nil {
|
||||
t.Fatalf("ScanStruct(%s) returned error %v", tt.title, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(value.Interface(), tt.value) {
|
||||
t.Fatalf("ScanStruct(%s) returned %v, want %v", tt.title, value.Interface(), tt.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadScanStructArgs(t *testing.T) {
|
||||
x := []interface{}{"A", "b"}
|
||||
test := func(v interface{}) {
|
||||
if err := redis.ScanStruct(x, v); err == nil {
|
||||
t.Errorf("Expect error for ScanStruct(%T, %T)", x, v)
|
||||
}
|
||||
}
|
||||
|
||||
test(nil)
|
||||
|
||||
var v0 *struct{}
|
||||
test(v0)
|
||||
|
||||
var v1 int
|
||||
test(&v1)
|
||||
|
||||
x = x[:1]
|
||||
v2 := struct{ A string }{}
|
||||
test(&v2)
|
||||
}
|
||||
|
||||
var scanSliceTests = []struct {
|
||||
src []interface{}
|
||||
fieldNames []string
|
||||
ok bool
|
||||
dest interface{}
|
||||
}{
|
||||
{
|
||||
[]interface{}{[]byte("1"), nil, []byte("-1")},
|
||||
nil,
|
||||
true,
|
||||
[]int{1, 0, -1},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("1"), nil, []byte("2")},
|
||||
nil,
|
||||
true,
|
||||
[]uint{1, 0, 2},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("-1")},
|
||||
nil,
|
||||
false,
|
||||
[]uint{1},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("hello"), nil, []byte("world")},
|
||||
nil,
|
||||
true,
|
||||
[][]byte{[]byte("hello"), nil, []byte("world")},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("hello"), nil, []byte("world")},
|
||||
nil,
|
||||
true,
|
||||
[]string{"hello", "", "world"},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
|
||||
nil,
|
||||
true,
|
||||
[]struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("a1"), []byte("b1")},
|
||||
nil,
|
||||
false,
|
||||
[]struct{ A, B, C string }{{"a1", "b1", ""}},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
|
||||
nil,
|
||||
true,
|
||||
[]*struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
|
||||
[]string{"A", "B"},
|
||||
true,
|
||||
[]struct{ A, C, B string }{{"a1", "", "b1"}, {"a2", "", "b2"}},
|
||||
},
|
||||
{
|
||||
[]interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
|
||||
nil,
|
||||
false,
|
||||
[]struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
func TestScanSlice(t *testing.T) {
|
||||
for _, tt := range scanSliceTests {
|
||||
|
||||
typ := reflect.ValueOf(tt.dest).Type()
|
||||
dest := reflect.New(typ)
|
||||
|
||||
err := redis.ScanSlice(tt.src, dest.Interface(), tt.fieldNames...)
|
||||
if tt.ok != (err == nil) {
|
||||
t.Errorf("ScanSlice(%v, []%s, %v) returned error %v", tt.src, typ, tt.fieldNames, err)
|
||||
continue
|
||||
}
|
||||
if tt.ok && !reflect.DeepEqual(dest.Elem().Interface(), tt.dest) {
|
||||
t.Errorf("ScanSlice(src, []%s) returned %#v, want %#v", typ, dest.Elem().Interface(), tt.dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleScanSlice() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
|
||||
c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
|
||||
c.Send("HMSET", "album:3", "title", "Beat", "rating", 4)
|
||||
c.Send("LPUSH", "albums", "1")
|
||||
c.Send("LPUSH", "albums", "2")
|
||||
c.Send("LPUSH", "albums", "3")
|
||||
values, err := redis.Values(c.Do("SORT", "albums",
|
||||
"BY", "album:*->rating",
|
||||
"GET", "album:*->title",
|
||||
"GET", "album:*->rating"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var albums []struct {
|
||||
Title string
|
||||
Rating int
|
||||
}
|
||||
if err := redis.ScanSlice(values, &albums); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%v\n", albums)
|
||||
// Output:
|
||||
// [{Earthbound 1} {Beat 4} {Red 5}]
|
||||
}
|
||||
|
||||
var argsTests = []struct {
|
||||
title string
|
||||
actual redis.Args
|
||||
expected redis.Args
|
||||
}{
|
||||
{"struct ptr",
|
||||
redis.Args{}.AddFlat(&struct {
|
||||
I int `redis:"i"`
|
||||
U uint `redis:"u"`
|
||||
S string `redis:"s"`
|
||||
P []byte `redis:"p"`
|
||||
M map[string]string `redis:"m"`
|
||||
Bt bool
|
||||
Bf bool
|
||||
}{
|
||||
-1234, 5678, "hello", []byte("world"), map[string]string{"hello": "world"}, true, false,
|
||||
}),
|
||||
redis.Args{"i", int(-1234), "u", uint(5678), "s", "hello", "p", []byte("world"), "m", map[string]string{"hello": "world"}, "Bt", true, "Bf", false},
|
||||
},
|
||||
{"struct",
|
||||
redis.Args{}.AddFlat(struct{ I int }{123}),
|
||||
redis.Args{"I", 123},
|
||||
},
|
||||
{"slice",
|
||||
redis.Args{}.Add(1).AddFlat([]string{"a", "b", "c"}).Add(2),
|
||||
redis.Args{1, "a", "b", "c", 2},
|
||||
},
|
||||
{"struct omitempty",
|
||||
redis.Args{}.AddFlat(&struct {
|
||||
I int `redis:"i,omitempty"`
|
||||
U uint `redis:"u,omitempty"`
|
||||
S string `redis:"s,omitempty"`
|
||||
P []byte `redis:"p,omitempty"`
|
||||
M map[string]string `redis:"m,omitempty"`
|
||||
Bt bool `redis:"Bt,omitempty"`
|
||||
Bf bool `redis:"Bf,omitempty"`
|
||||
}{
|
||||
0, 0, "", []byte{}, map[string]string{}, true, false,
|
||||
}),
|
||||
redis.Args{"Bt", true},
|
||||
},
|
||||
}
|
||||
|
||||
func TestArgs(t *testing.T) {
|
||||
for _, tt := range argsTests {
|
||||
if !reflect.DeepEqual(tt.actual, tt.expected) {
|
||||
t.Fatalf("%s is %v, want %v", tt.title, tt.actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleArgs() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var p1, p2 struct {
|
||||
Title string `redis:"title"`
|
||||
Author string `redis:"author"`
|
||||
Body string `redis:"body"`
|
||||
}
|
||||
|
||||
p1.Title = "Example"
|
||||
p1.Author = "Gary"
|
||||
p1.Body = "Hello"
|
||||
|
||||
if _, err := c.Do("HMSET", redis.Args{}.Add("id1").AddFlat(&p1)...); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
m := map[string]string{
|
||||
"title": "Example2",
|
||||
"author": "Steve",
|
||||
"body": "Map",
|
||||
}
|
||||
|
||||
if _, err := c.Do("HMSET", redis.Args{}.Add("id2").AddFlat(m)...); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, id := range []string{"id1", "id2"} {
|
||||
|
||||
v, err := redis.Values(c.Do("HGETALL", id))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := redis.ScanStruct(v, &p2); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", p2)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {Title:Example Author:Gary Body:Hello}
|
||||
// {Title:Example2 Author:Steve Body:Map}
|
||||
}
|
||||
100
vendor/github.com/garyburd/redigo/redis/script_test.go
generated
vendored
Normal file
100
vendor/github.com/garyburd/redigo/redis/script_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
var (
|
||||
// These variables are declared at package level to remove distracting
|
||||
// details from the examples.
|
||||
c redis.Conn
|
||||
reply interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
func ExampleScript() {
|
||||
// Initialize a package-level variable with a script.
|
||||
var getScript = redis.NewScript(1, `return redis.call('get', KEYS[1])`)
|
||||
|
||||
// In a function, use the script Do method to evaluate the script. The Do
|
||||
// method optimistically uses the EVALSHA command. If the script is not
|
||||
// loaded, then the Do method falls back to the EVAL command.
|
||||
reply, err = getScript.Do(c, "foo")
|
||||
}
|
||||
|
||||
func TestScript(t *testing.T) {
|
||||
c, err := redis.DialDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
// To test fall back in Do, we make script unique by adding comment with current time.
|
||||
script := fmt.Sprintf("--%d\nreturn {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", time.Now().UnixNano())
|
||||
s := redis.NewScript(2, script)
|
||||
reply := []interface{}{[]byte("key1"), []byte("key2"), []byte("arg1"), []byte("arg2")}
|
||||
|
||||
v, err := s.Do(c, "key1", "key2", "arg1", "arg2")
|
||||
if err != nil {
|
||||
t.Errorf("s.Do(c, ...) returned %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(v, reply) {
|
||||
t.Errorf("s.Do(c, ..); = %v, want %v", v, reply)
|
||||
}
|
||||
|
||||
err = s.Load(c)
|
||||
if err != nil {
|
||||
t.Errorf("s.Load(c) returned %v", err)
|
||||
}
|
||||
|
||||
err = s.SendHash(c, "key1", "key2", "arg1", "arg2")
|
||||
if err != nil {
|
||||
t.Errorf("s.SendHash(c, ...) returned %v", err)
|
||||
}
|
||||
|
||||
err = c.Flush()
|
||||
if err != nil {
|
||||
t.Errorf("c.Flush() returned %v", err)
|
||||
}
|
||||
|
||||
v, err = c.Receive()
|
||||
if !reflect.DeepEqual(v, reply) {
|
||||
t.Errorf("s.SendHash(c, ..); c.Receive() = %v, want %v", v, reply)
|
||||
}
|
||||
|
||||
err = s.Send(c, "key1", "key2", "arg1", "arg2")
|
||||
if err != nil {
|
||||
t.Errorf("s.Send(c, ...) returned %v", err)
|
||||
}
|
||||
|
||||
err = c.Flush()
|
||||
if err != nil {
|
||||
t.Errorf("c.Flush() returned %v", err)
|
||||
}
|
||||
|
||||
v, err = c.Receive()
|
||||
if !reflect.DeepEqual(v, reply) {
|
||||
t.Errorf("s.Send(c, ..); c.Receive() = %v, want %v", v, reply)
|
||||
}
|
||||
|
||||
}
|
||||
177
vendor/github.com/garyburd/redigo/redis/test_test.go
generated
vendored
Normal file
177
vendor/github.com/garyburd/redigo/redis/test_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SetNowFunc(f func() time.Time) {
|
||||
nowFunc = f
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNegativeInt = errNegativeInt
|
||||
|
||||
serverPath = flag.String("redis-server", "redis-server", "Path to redis server binary")
|
||||
serverBasePort = flag.Int("redis-port", 16379, "Beginning of port range for test servers")
|
||||
serverLogName = flag.String("redis-log", "", "Write Redis server logs to `filename`")
|
||||
serverLog = ioutil.Discard
|
||||
|
||||
defaultServerMu sync.Mutex
|
||||
defaultServer *Server
|
||||
defaultServerErr error
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
name string
|
||||
cmd *exec.Cmd
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewServer(name string, args ...string) (*Server, error) {
|
||||
s := &Server{
|
||||
name: name,
|
||||
cmd: exec.Command(*serverPath, args...),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
r, err := s.cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.cmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ready := make(chan error, 1)
|
||||
go s.watch(r, ready)
|
||||
|
||||
select {
|
||||
case err = <-ready:
|
||||
case <-time.After(time.Second * 10):
|
||||
err = errors.New("timeout waiting for server to start")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
s.Stop()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) watch(r io.Reader, ready chan error) {
|
||||
fmt.Fprintf(serverLog, "%d START %s \n", s.cmd.Process.Pid, s.name)
|
||||
var listening bool
|
||||
var text string
|
||||
scn := bufio.NewScanner(r)
|
||||
for scn.Scan() {
|
||||
text = scn.Text()
|
||||
fmt.Fprintf(serverLog, "%s\n", text)
|
||||
if !listening {
|
||||
if strings.Contains(text, "The server is now ready to accept connections on port") {
|
||||
listening = true
|
||||
ready <- nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if !listening {
|
||||
ready <- fmt.Errorf("server exited: %s", text)
|
||||
}
|
||||
s.cmd.Wait()
|
||||
fmt.Fprintf(serverLog, "%d STOP %s \n", s.cmd.Process.Pid, s.name)
|
||||
close(s.done)
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
s.cmd.Process.Signal(os.Interrupt)
|
||||
<-s.done
|
||||
}
|
||||
|
||||
// stopDefaultServer stops the server created by DialDefaultServer.
|
||||
func stopDefaultServer() {
|
||||
defaultServerMu.Lock()
|
||||
defer defaultServerMu.Unlock()
|
||||
if defaultServer != nil {
|
||||
defaultServer.Stop()
|
||||
defaultServer = nil
|
||||
}
|
||||
}
|
||||
|
||||
// startDefaultServer starts the default server if not already running.
|
||||
func startDefaultServer() error {
|
||||
defaultServerMu.Lock()
|
||||
defer defaultServerMu.Unlock()
|
||||
if defaultServer != nil || defaultServerErr != nil {
|
||||
return defaultServerErr
|
||||
}
|
||||
defaultServer, defaultServerErr = NewServer(
|
||||
"default",
|
||||
"--port", strconv.Itoa(*serverBasePort),
|
||||
"--save", "",
|
||||
"--appendonly", "no")
|
||||
return defaultServerErr
|
||||
}
|
||||
|
||||
// DialDefaultServer starts the test server if not already started and dials a
|
||||
// connection to the server.
|
||||
func DialDefaultServer() (Conn, error) {
|
||||
if err := startDefaultServer(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := Dial("tcp", fmt.Sprintf(":%d", *serverBasePort), DialReadTimeout(1*time.Second), DialWriteTimeout(1*time.Second))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Do("FLUSHDB")
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
flag.Parse()
|
||||
|
||||
var f *os.File
|
||||
if *serverLogName != "" {
|
||||
var err error
|
||||
f, err = os.OpenFile(*serverLogName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error opening redis-log: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
defer f.Close()
|
||||
serverLog = f
|
||||
}
|
||||
|
||||
defer stopDefaultServer()
|
||||
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
||||
113
vendor/github.com/garyburd/redigo/redis/zpop_example_test.go
generated
vendored
Normal file
113
vendor/github.com/garyburd/redigo/redis/zpop_example_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2013 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redis_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands.
|
||||
func zpop(c redis.Conn, key string) (result string, err error) {
|
||||
|
||||
defer func() {
|
||||
// Return connection to normal state on error.
|
||||
if err != nil {
|
||||
c.Do("DISCARD")
|
||||
}
|
||||
}()
|
||||
|
||||
// Loop until transaction is successful.
|
||||
for {
|
||||
if _, err := c.Do("WATCH", key); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(members) != 1 {
|
||||
return "", redis.ErrNil
|
||||
}
|
||||
|
||||
c.Send("MULTI")
|
||||
c.Send("ZREM", key, members[0])
|
||||
queued, err := c.Do("EXEC")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if queued != nil {
|
||||
result = members[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// zpopScript pops a value from a ZSET.
|
||||
var zpopScript = redis.NewScript(1, `
|
||||
local r = redis.call('ZRANGE', KEYS[1], 0, 0)
|
||||
if r ~= nil then
|
||||
r = r[1]
|
||||
redis.call('ZREM', KEYS[1], r)
|
||||
end
|
||||
return r
|
||||
`)
|
||||
|
||||
// This example implements ZPOP as described at
|
||||
// http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting.
|
||||
func Example_zpop() {
|
||||
c, err := dial()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
// Add test data using a pipeline.
|
||||
|
||||
for i, member := range []string{"red", "blue", "green"} {
|
||||
c.Send("ZADD", "zset", i, member)
|
||||
}
|
||||
if _, err := c.Do(""); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Pop using WATCH/MULTI/EXEC
|
||||
|
||||
v, err := zpop(c, "zset")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(v)
|
||||
|
||||
// Pop using a script.
|
||||
|
||||
v, err = redis.String(zpopScript.Do(c, "zset"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(v)
|
||||
|
||||
// Output:
|
||||
// red
|
||||
// blue
|
||||
}
|
||||
152
vendor/github.com/garyburd/redigo/redisx/connmux.go
generated
vendored
Normal file
152
vendor/github.com/garyburd/redigo/redisx/connmux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2014 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redisx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/garyburd/redigo/internal"
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
// ConnMux multiplexes one or more connections to a single underlying
|
||||
// connection. The ConnMux connections do not support concurrency, commands
|
||||
// that associate server side state with the connection or commands that put
|
||||
// the connection in a special mode.
|
||||
type ConnMux struct {
|
||||
c redis.Conn
|
||||
|
||||
sendMu sync.Mutex
|
||||
sendID uint
|
||||
|
||||
recvMu sync.Mutex
|
||||
recvID uint
|
||||
recvWait map[uint]chan struct{}
|
||||
}
|
||||
|
||||
func NewConnMux(c redis.Conn) *ConnMux {
|
||||
return &ConnMux{c: c, recvWait: make(map[uint]chan struct{})}
|
||||
}
|
||||
|
||||
// Get gets a connection. The application must close the returned connection.
|
||||
func (p *ConnMux) Get() redis.Conn {
|
||||
c := &muxConn{p: p}
|
||||
c.ids = c.buf[:0]
|
||||
return c
|
||||
}
|
||||
|
||||
// Close closes the underlying connection.
|
||||
func (p *ConnMux) Close() error {
|
||||
return p.c.Close()
|
||||
}
|
||||
|
||||
type muxConn struct {
|
||||
p *ConnMux
|
||||
ids []uint
|
||||
buf [8]uint
|
||||
}
|
||||
|
||||
func (c *muxConn) send(flush bool, cmd string, args ...interface{}) error {
|
||||
if internal.LookupCommandInfo(cmd).Set != 0 {
|
||||
return errors.New("command not supported by mux pool")
|
||||
}
|
||||
p := c.p
|
||||
p.sendMu.Lock()
|
||||
id := p.sendID
|
||||
c.ids = append(c.ids, id)
|
||||
p.sendID++
|
||||
err := p.c.Send(cmd, args...)
|
||||
if flush {
|
||||
err = p.c.Flush()
|
||||
}
|
||||
p.sendMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *muxConn) Send(cmd string, args ...interface{}) error {
|
||||
return c.send(false, cmd, args...)
|
||||
}
|
||||
|
||||
func (c *muxConn) Flush() error {
|
||||
p := c.p
|
||||
p.sendMu.Lock()
|
||||
err := p.c.Flush()
|
||||
p.sendMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *muxConn) Receive() (interface{}, error) {
|
||||
if len(c.ids) == 0 {
|
||||
return nil, errors.New("mux pool underflow")
|
||||
}
|
||||
|
||||
id := c.ids[0]
|
||||
c.ids = c.ids[1:]
|
||||
if len(c.ids) == 0 {
|
||||
c.ids = c.buf[:0]
|
||||
}
|
||||
|
||||
p := c.p
|
||||
p.recvMu.Lock()
|
||||
if p.recvID != id {
|
||||
ch := make(chan struct{})
|
||||
p.recvWait[id] = ch
|
||||
p.recvMu.Unlock()
|
||||
<-ch
|
||||
p.recvMu.Lock()
|
||||
if p.recvID != id {
|
||||
panic("out of sync")
|
||||
}
|
||||
}
|
||||
|
||||
v, err := p.c.Receive()
|
||||
|
||||
id++
|
||||
p.recvID = id
|
||||
ch, ok := p.recvWait[id]
|
||||
if ok {
|
||||
delete(p.recvWait, id)
|
||||
}
|
||||
p.recvMu.Unlock()
|
||||
if ok {
|
||||
ch <- struct{}{}
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (c *muxConn) Close() error {
|
||||
var err error
|
||||
if len(c.ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
c.Flush()
|
||||
for _ = range c.ids {
|
||||
_, err = c.Receive()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *muxConn) Do(cmd string, args ...interface{}) (interface{}, error) {
|
||||
if err := c.send(true, cmd, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Receive()
|
||||
}
|
||||
|
||||
func (c *muxConn) Err() error {
|
||||
return c.p.c.Err()
|
||||
}
|
||||
259
vendor/github.com/garyburd/redigo/redisx/connmux_test.go
generated
vendored
Normal file
259
vendor/github.com/garyburd/redigo/redisx/connmux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
// Copyright 2014 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package redisx_test
|
||||
|
||||
import (
|
||||
"net/textproto"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/garyburd/redigo/internal/redistest"
|
||||
"github.com/garyburd/redigo/redis"
|
||||
"github.com/garyburd/redigo/redisx"
|
||||
)
|
||||
|
||||
func TestConnMux(t *testing.T) {
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
m := redisx.NewConnMux(c)
|
||||
defer m.Close()
|
||||
|
||||
c1 := m.Get()
|
||||
c2 := m.Get()
|
||||
c1.Send("ECHO", "hello")
|
||||
c2.Send("ECHO", "world")
|
||||
c1.Flush()
|
||||
c2.Flush()
|
||||
s, err := redis.String(c1.Receive())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s != "hello" {
|
||||
t.Fatalf("echo returned %q, want %q", s, "hello")
|
||||
}
|
||||
s, err = redis.String(c2.Receive())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s != "world" {
|
||||
t.Fatalf("echo returned %q, want %q", s, "world")
|
||||
}
|
||||
c1.Close()
|
||||
c2.Close()
|
||||
}
|
||||
|
||||
func TestConnMuxClose(t *testing.T) {
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
t.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
m := redisx.NewConnMux(c)
|
||||
defer m.Close()
|
||||
|
||||
c1 := m.Get()
|
||||
c2 := m.Get()
|
||||
|
||||
if err := c1.Send("ECHO", "hello"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := c1.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c2.Send("ECHO", "world"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := c2.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := redis.String(c2.Receive())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s != "world" {
|
||||
t.Fatalf("echo returned %q, want %q", s, "world")
|
||||
}
|
||||
c2.Close()
|
||||
}
|
||||
|
||||
func BenchmarkConn(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
b.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConnMux(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
b.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
m := redisx.NewConnMux(c)
|
||||
defer m.Close()
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := m.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPool(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
p := redis.Pool{Dial: redistest.Dial, MaxIdle: 1}
|
||||
defer p.Close()
|
||||
|
||||
// Fill the pool.
|
||||
c := p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := p.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
const numConcurrent = 10
|
||||
|
||||
func BenchmarkConnMuxConcurrent(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
b.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
m := redisx.NewConnMux(c)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numConcurrent)
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < numConcurrent; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := m.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkPoolConcurrent(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
p := redis.Pool{Dial: redistest.Dial, MaxIdle: numConcurrent}
|
||||
defer p.Close()
|
||||
|
||||
// Fill the pool.
|
||||
conns := make([]redis.Conn, numConcurrent)
|
||||
for i := range conns {
|
||||
c := p.Get()
|
||||
if err := c.Err(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
conns[i] = c
|
||||
}
|
||||
for _, c := range conns {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numConcurrent)
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < numConcurrent; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := p.Get()
|
||||
if _, err := c.Do("PING"); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkPipelineConcurrency(b *testing.B) {
|
||||
b.StopTimer()
|
||||
c, err := redistest.Dial()
|
||||
if err != nil {
|
||||
b.Fatalf("error connection to database, %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numConcurrent)
|
||||
|
||||
var pipeline textproto.Pipeline
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < numConcurrent; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < b.N; i++ {
|
||||
id := pipeline.Next()
|
||||
pipeline.StartRequest(id)
|
||||
c.Send("PING")
|
||||
c.Flush()
|
||||
pipeline.EndRequest(id)
|
||||
pipeline.StartResponse(id)
|
||||
_, err := c.Receive()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
pipeline.EndResponse(id)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
17
vendor/github.com/garyburd/redigo/redisx/doc.go
generated
vendored
Normal file
17
vendor/github.com/garyburd/redigo/redisx/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
// Package redisx contains experimental features for Redigo. Features in this
|
||||
// package may be modified or deleted at any time.
|
||||
package redisx // import "github.com/garyburd/redigo/redisx"
|
||||
204
vendor/github.com/go-gorp/gorp/dialect_mysql_test.go
generated
vendored
Normal file
204
vendor/github.com/go-gorp/gorp/dialect_mysql_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp_test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
// ginkgo/gomega functions read better as dot-imports.
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/extensions/table"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/go-gorp/gorp"
|
||||
)
|
||||
|
||||
var _ = Describe("MySQLDialect", func() {
|
||||
var (
|
||||
engine, encoding string
|
||||
dialect gorp.MySQLDialect
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
dialect = gorp.MySQLDialect{
|
||||
Engine: engine,
|
||||
Encoding: encoding,
|
||||
}
|
||||
})
|
||||
|
||||
DescribeTable("ToSqlType",
|
||||
func(value interface{}, maxsize int, autoIncr bool, expected string) {
|
||||
typ := reflect.TypeOf(value)
|
||||
sqlType := dialect.ToSqlType(typ, maxsize, autoIncr)
|
||||
Expect(sqlType).To(Equal(expected))
|
||||
},
|
||||
Entry("bool", true, 0, false, "boolean"),
|
||||
Entry("int8", int8(1), 0, false, "tinyint"),
|
||||
Entry("uint8", uint8(1), 0, false, "tinyint unsigned"),
|
||||
Entry("int16", int16(1), 0, false, "smallint"),
|
||||
Entry("uint16", uint16(1), 0, false, "smallint unsigned"),
|
||||
Entry("int32", int32(1), 0, false, "int"),
|
||||
Entry("int (treated as int32)", int(1), 0, false, "int"),
|
||||
Entry("uint32", uint32(1), 0, false, "int unsigned"),
|
||||
Entry("uint (treated as uint32)", uint(1), 0, false, "int unsigned"),
|
||||
Entry("int64", int64(1), 0, false, "bigint"),
|
||||
Entry("uint64", uint64(1), 0, false, "bigint unsigned"),
|
||||
Entry("float32", float32(1), 0, false, "double"),
|
||||
Entry("float64", float64(1), 0, false, "double"),
|
||||
Entry("[]uint8", []uint8{1}, 0, false, "mediumblob"),
|
||||
Entry("NullInt64", sql.NullInt64{}, 0, false, "bigint"),
|
||||
Entry("NullFloat64", sql.NullFloat64{}, 0, false, "double"),
|
||||
Entry("NullBool", sql.NullBool{}, 0, false, "tinyint"),
|
||||
Entry("Time", time.Time{}, 0, false, "datetime"),
|
||||
Entry("default-size string", "", 0, false, "varchar(255)"),
|
||||
Entry("sized string", "", 50, false, "varchar(50)"),
|
||||
Entry("large string", "", 1024, false, "text"),
|
||||
)
|
||||
|
||||
Describe("AutoIncrStr", func() {
|
||||
It("returns the auto increment string", func() {
|
||||
Expect(dialect.AutoIncrStr()).To(Equal("auto_increment"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("AutoIncrBindValue", func() {
|
||||
It("returns the value used to bind the auto-increment value", func() {
|
||||
Expect(dialect.AutoIncrBindValue()).To(Equal("null"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("AutoIncrInsertSuffix", func() {
|
||||
It("returns the suffix needed for auto-incrementing", func() {
|
||||
Expect(dialect.AutoIncrInsertSuffix(nil)).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("CreateTableSuffix", func() {
|
||||
Context("with an empty engine", func() {
|
||||
BeforeEach(func() {
|
||||
engine = ""
|
||||
encoding = "foo"
|
||||
})
|
||||
It("panics", func() {
|
||||
Expect(func() {
|
||||
dialect.CreateTableSuffix()
|
||||
}).To(Panic())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with an empty encoding", func() {
|
||||
BeforeEach(func() {
|
||||
engine = "foo"
|
||||
encoding = ""
|
||||
})
|
||||
It("panics", func() {
|
||||
Expect(func() {
|
||||
dialect.CreateTableSuffix()
|
||||
}).To(Panic())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with an engine and an encoding", func() {
|
||||
BeforeEach(func() {
|
||||
engine = "foo"
|
||||
encoding = "bar"
|
||||
})
|
||||
It("returns a valid suffix", func() {
|
||||
Expect(dialect.CreateTableSuffix()).To(Equal(" engine=foo charset=bar"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("CreateIndexSuffix", func() {
|
||||
It("returns the suffix for creating indexes", func() {
|
||||
Expect(dialect.CreateIndexSuffix()).To(Equal("using"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("DropIndexSuffix", func() {
|
||||
It("returns the suffix for deleting indexes", func() {
|
||||
Expect(dialect.DropIndexSuffix()).To(Equal("on"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("TruncateClause", func() {
|
||||
It("returns the clause for truncating a table", func() {
|
||||
Expect(dialect.TruncateClause()).To(Equal("truncate"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("BindVar", func() {
|
||||
It("returns the variable binding sequence", func() {
|
||||
Expect(dialect.BindVar(0)).To(Equal("?"))
|
||||
})
|
||||
})
|
||||
|
||||
PDescribe("InsertAutoIncr", func() {})
|
||||
|
||||
Describe("QuoteField", func() {
|
||||
It("returns the argument quoted as a field", func() {
|
||||
Expect(dialect.QuoteField("foo")).To(Equal("`foo`"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("QuotedTableForQuery", func() {
|
||||
var (
|
||||
schema, table string
|
||||
|
||||
quotedTable string
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
quotedTable = dialect.QuotedTableForQuery(schema, table)
|
||||
})
|
||||
|
||||
Context("using the default schema", func() {
|
||||
BeforeEach(func() {
|
||||
schema = ""
|
||||
table = "foo"
|
||||
})
|
||||
It("returns just the table", func() {
|
||||
Expect(quotedTable).To(Equal("`foo`"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with a supplied schema", func() {
|
||||
BeforeEach(func() {
|
||||
schema = "foo"
|
||||
table = "bar"
|
||||
})
|
||||
It("returns the schema and table", func() {
|
||||
Expect(quotedTable).To(Equal("foo.`bar`"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("IfSchemaNotExists", func() {
|
||||
It("appends 'if not exists' to the command", func() {
|
||||
Expect(dialect.IfSchemaNotExists("foo", "bar")).To(Equal("foo if not exists"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("IfTableExists", func() {
|
||||
It("appends 'if exists' to the command", func() {
|
||||
Expect(dialect.IfTableExists("foo", "bar", "baz")).To(Equal("foo if exists"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("IfTableNotExists", func() {
|
||||
It("appends 'if not exists' to the command", func() {
|
||||
Expect(dialect.IfTableNotExists("foo", "bar", "baz")).To(Equal("foo if not exists"))
|
||||
})
|
||||
})
|
||||
})
|
||||
13
vendor/github.com/go-gorp/gorp/gorp_suite_test.go
generated
vendored
Normal file
13
vendor/github.com/go-gorp/gorp/gorp_suite_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package gorp_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGorp(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Gorp Suite")
|
||||
}
|
||||
2412
vendor/github.com/go-gorp/gorp/gorp_test.go
generated
vendored
Normal file
2412
vendor/github.com/go-gorp/gorp/gorp_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
0
vendor/github.com/go-gorp/gorp/test_all.sh
generated
vendored
Normal file → Executable file
0
vendor/github.com/go-gorp/gorp/test_all.sh
generated
vendored
Normal file → Executable file
53
vendor/github.com/go-ldap/ldap/conn_test.go
generated
vendored
Normal file
53
vendor/github.com/go-ldap/ldap/conn_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package ldap
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
func TestUnresponsiveConnection(t *testing.T) {
|
||||
// The do-nothing server that accepts requests and does nothing
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
c, err := net.Dial(ts.Listener.Addr().Network(), ts.Listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatalf("error connecting to localhost tcp: %v", err)
|
||||
}
|
||||
|
||||
// Create an Ldap connection
|
||||
conn := NewConn(c, false)
|
||||
conn.SetTimeout(time.Millisecond)
|
||||
conn.Start()
|
||||
defer conn.Close()
|
||||
|
||||
// Mock a packet
|
||||
messageID := conn.nextMessageID()
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
||||
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
||||
packet.AppendChild(bindRequest)
|
||||
|
||||
// Send packet and test response
|
||||
channel, err := conn.sendMessage(packet)
|
||||
if err != nil {
|
||||
t.Fatalf("error sending message: %v", err)
|
||||
}
|
||||
packetResponse, ok := <-channel
|
||||
if !ok {
|
||||
t.Fatalf("no PacketResponse in response channel")
|
||||
}
|
||||
packet, err = packetResponse.ReadPacket()
|
||||
if err == nil {
|
||||
t.Fatalf("expected timeout error")
|
||||
}
|
||||
if err.Error() != "ldap: connection timed out" {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
70
vendor/github.com/go-ldap/ldap/dn_test.go
generated
vendored
Normal file
70
vendor/github.com/go-ldap/ldap/dn_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package ldap_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
func TestSuccessfulDNParsing(t *testing.T) {
|
||||
testcases := map[string]ldap.DN{
|
||||
"": ldap.DN{[]*ldap.RelativeDN{}},
|
||||
"cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "dummy"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "com"}}}}},
|
||||
"UID=jsmith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"UID", "jsmith"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||
"OU=Sales+CN=J. Smith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
|
||||
&ldap.AttributeTypeAndValue{"OU", "Sales"},
|
||||
&ldap.AttributeTypeAndValue{"CN", "J. Smith"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||
"1.3.6.1.4.1.1466.0=#04024869": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}}},
|
||||
"1.3.6.1.4.1.1466.0=#04024869,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}},
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||
"CN=Lu\\C4\\8Di\\C4\\87": ldap.DN{[]*ldap.RelativeDN{
|
||||
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}},
|
||||
}
|
||||
|
||||
for test, answer := range testcases {
|
||||
dn, err := ldap.ParseDN(test)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(dn, &answer) {
|
||||
t.Errorf("Parsed DN %s is not equal to the expected structure", test)
|
||||
for _, rdn := range dn.RDNs {
|
||||
for _, attribs := range rdn.Attributes {
|
||||
t.Logf("#%v\n", attribs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorDNParsing(t *testing.T) {
|
||||
testcases := map[string]string{
|
||||
"*": "DN ended with incomplete type, value pair",
|
||||
"cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
|
||||
"cn=Jim\\0": "Got corrupted escaped character",
|
||||
"DC=example,=net": "DN ended with incomplete type, value pair",
|
||||
"1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string",
|
||||
}
|
||||
|
||||
for test, answer := range testcases {
|
||||
_, err := ldap.ParseDN(test)
|
||||
if err == nil {
|
||||
t.Errorf("Expected %s to fail parsing but succeeded\n", test)
|
||||
} else if err.Error() != answer {
|
||||
t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/go-ldap/ldap/error_test.go
generated
vendored
Normal file
29
vendor/github.com/go-ldap/ldap/error_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package ldap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
// TestNilPacket tests that nil packets don't cause a panic.
|
||||
func TestNilPacket(t *testing.T) {
|
||||
// Test for nil packet
|
||||
code, _ := getLDAPResultCode(nil)
|
||||
if code != ErrorUnexpectedResponse {
|
||||
t.Errorf("Should have an 'ErrorUnexpectedResponse' error in nil packets, got: %v", code)
|
||||
}
|
||||
|
||||
// Test for nil result
|
||||
kids := []*ber.Packet{
|
||||
&ber.Packet{}, // Unused
|
||||
nil, // Can't be nil
|
||||
}
|
||||
pack := &ber.Packet{Children: kids}
|
||||
code, _ = getLDAPResultCode(pack)
|
||||
|
||||
if code != ErrorUnexpectedResponse {
|
||||
t.Errorf("Should have an 'ErrorUnexpectedResponse' error in nil packets, got: %v", code)
|
||||
}
|
||||
|
||||
}
|
||||
305
vendor/github.com/go-ldap/ldap/example_test.go
generated
vendored
Normal file
305
vendor/github.com/go-ldap/ldap/example_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
package ldap_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
// ExampleConn_Bind demonstrates how to bind a connection to an ldap user
|
||||
// allowing access to restricted attrabutes that user has access to
|
||||
func ExampleConn_Bind() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// ExampleConn_Search demonstrates how to use the search interface
|
||||
func ExampleConn_Search() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
"dc=example,dc=com", // The base dn to search
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))", // The filter to apply
|
||||
[]string{"dn", "cn"}, // A list attributes to retrieve
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, entry := range sr.Entries {
|
||||
fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
|
||||
}
|
||||
}
|
||||
|
||||
// ExampleStartTLS demonstrates how to start a TLS connection
|
||||
func ExampleConn_StartTLS() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Reconnect with TLS
|
||||
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Opertations via l are now encrypted
|
||||
}
|
||||
|
||||
// ExampleConn_Compare demonstrates how to comapre an attribute with a value
|
||||
func ExampleConn_Compare() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(matched)
|
||||
}
|
||||
|
||||
func ExampleConn_PasswordModify_admin() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("cn=admin,dc=example,dc=com", "password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
passwordModifyRequest := ldap.NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword")
|
||||
_, err = l.PasswordModify(passwordModifyRequest)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleConn_PasswordModify_generatedPassword() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("cn=user,dc=example,dc=com", "password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "")
|
||||
passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest)
|
||||
if err != nil {
|
||||
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||
}
|
||||
|
||||
generatedPassword := passwordModifyResponse.GeneratedPassword
|
||||
log.Printf("Generated password: %s\n", generatedPassword)
|
||||
}
|
||||
|
||||
func ExampleConn_PasswordModify_setNewPassword() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("cn=user,dc=example,dc=com", "password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "NewPassword")
|
||||
_, err = l.PasswordModify(passwordModifyRequest)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleConn_Modify() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Add a description, and replace the mail attributes
|
||||
modify := ldap.NewModifyRequest("cn=user,dc=example,dc=com")
|
||||
modify.Add("description", []string{"An example user"})
|
||||
modify.Replace("mail", []string{"user@example.org"})
|
||||
|
||||
err = l.Modify(modify)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Example User Authentication shows how a typical application can verify a login attempt
|
||||
func Example_userAuthentication() {
|
||||
// The username and password we want to check
|
||||
username := "someuser"
|
||||
password := "userpassword"
|
||||
|
||||
bindusername := "readonly"
|
||||
bindpassword := "password"
|
||||
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Reconnect with TLS
|
||||
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// First bind with a read only user
|
||||
err = l.Bind(bindusername, bindpassword)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Search for the given username
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
"dc=example,dc=com",
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=organizationalPerson)&(uid=%s))", username),
|
||||
[]string{"dn"},
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(sr.Entries) != 1 {
|
||||
log.Fatal("User does not exist or too many entries returned")
|
||||
}
|
||||
|
||||
userdn := sr.Entries[0].DN
|
||||
|
||||
// Bind as the user to verify their password
|
||||
err = l.Bind(userdn, password)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Rebind as the read only user for any futher queries
|
||||
err = l.Bind(bindusername, bindpassword)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Example_beherappolicy() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
controls := []ldap.Control{}
|
||||
controls = append(controls, ldap.NewControlBeheraPasswordPolicy())
|
||||
bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls)
|
||||
|
||||
r, err := l.SimpleBind(bindRequest)
|
||||
ppolicyControl := ldap.FindControl(r.Controls, ldap.ControlTypeBeheraPasswordPolicy)
|
||||
|
||||
var ppolicy *ldap.ControlBeheraPasswordPolicy
|
||||
if ppolicyControl != nil {
|
||||
ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy)
|
||||
} else {
|
||||
log.Printf("ppolicyControl response not avaliable.\n")
|
||||
}
|
||||
if err != nil {
|
||||
errStr := "ERROR: Cannot bind: " + err.Error()
|
||||
if ppolicy != nil && ppolicy.Error >= 0 {
|
||||
errStr += ":" + ppolicy.ErrorString
|
||||
}
|
||||
log.Print(errStr)
|
||||
} else {
|
||||
logStr := "Login Ok"
|
||||
if ppolicy != nil {
|
||||
if ppolicy.Expire >= 0 {
|
||||
logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire)
|
||||
} else if ppolicy.Grace >= 0 {
|
||||
logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace)
|
||||
}
|
||||
}
|
||||
log.Print(logStr)
|
||||
}
|
||||
}
|
||||
|
||||
func Example_vchuppolicy() {
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
l.Debug = true
|
||||
|
||||
bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil)
|
||||
|
||||
r, err := l.SimpleBind(bindRequest)
|
||||
|
||||
passwordMustChangeControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordMustChange)
|
||||
var passwordMustChange *ldap.ControlVChuPasswordMustChange
|
||||
if passwordMustChangeControl != nil {
|
||||
passwordMustChange = passwordMustChangeControl.(*ldap.ControlVChuPasswordMustChange)
|
||||
}
|
||||
|
||||
if passwordMustChange != nil && passwordMustChange.MustChange {
|
||||
log.Printf("Password Must be changed.\n")
|
||||
}
|
||||
|
||||
passwordWarningControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordWarning)
|
||||
|
||||
var passwordWarning *ldap.ControlVChuPasswordWarning
|
||||
if passwordWarningControl != nil {
|
||||
passwordWarning = passwordWarningControl.(*ldap.ControlVChuPasswordWarning)
|
||||
} else {
|
||||
log.Printf("ppolicyControl response not available.\n")
|
||||
}
|
||||
if err != nil {
|
||||
log.Print("ERROR: Cannot bind: " + err.Error())
|
||||
} else {
|
||||
logStr := "Login Ok"
|
||||
if passwordWarning != nil {
|
||||
if passwordWarning.Expire >= 0 {
|
||||
logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire)
|
||||
}
|
||||
}
|
||||
log.Print(logStr)
|
||||
}
|
||||
}
|
||||
248
vendor/github.com/go-ldap/ldap/filter_test.go
generated
vendored
Normal file
248
vendor/github.com/go-ldap/ldap/filter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
package ldap_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
type compileTest struct {
|
||||
filterStr string
|
||||
|
||||
expectedFilter string
|
||||
expectedType int
|
||||
expectedErr string
|
||||
}
|
||||
|
||||
var testFilters = []compileTest{
|
||||
compileTest{
|
||||
filterStr: "(&(sn=Miller)(givenName=Bob))",
|
||||
expectedFilter: "(&(sn=Miller)(givenName=Bob))",
|
||||
expectedType: ldap.FilterAnd,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(|(sn=Miller)(givenName=Bob))",
|
||||
expectedFilter: "(|(sn=Miller)(givenName=Bob))",
|
||||
expectedType: ldap.FilterOr,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(!(sn=Miller))",
|
||||
expectedFilter: "(!(sn=Miller))",
|
||||
expectedType: ldap.FilterNot,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=Miller)",
|
||||
expectedFilter: "(sn=Miller)",
|
||||
expectedType: ldap.FilterEqualityMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=Mill*)",
|
||||
expectedFilter: "(sn=Mill*)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=*Mill)",
|
||||
expectedFilter: "(sn=*Mill)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=*Mill*)",
|
||||
expectedFilter: "(sn=*Mill*)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=*i*le*)",
|
||||
expectedFilter: "(sn=*i*le*)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=Mi*l*r)",
|
||||
expectedFilter: "(sn=Mi*l*r)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
// substring filters escape properly
|
||||
compileTest{
|
||||
filterStr: `(sn=Mi*함*r)`,
|
||||
expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
// already escaped substring filters don't get double-escaped
|
||||
compileTest{
|
||||
filterStr: `(sn=Mi*\ed\95\a8*r)`,
|
||||
expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=Mi*le*)",
|
||||
expectedFilter: "(sn=Mi*le*)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=*i*ler)",
|
||||
expectedFilter: "(sn=*i*ler)",
|
||||
expectedType: ldap.FilterSubstrings,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn>=Miller)",
|
||||
expectedFilter: "(sn>=Miller)",
|
||||
expectedType: ldap.FilterGreaterOrEqual,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn<=Miller)",
|
||||
expectedFilter: "(sn<=Miller)",
|
||||
expectedType: ldap.FilterLessOrEqual,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn=*)",
|
||||
expectedFilter: "(sn=*)",
|
||||
expectedType: ldap.FilterPresent,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: "(sn~=Miller)",
|
||||
expectedFilter: "(sn~=Miller)",
|
||||
expectedType: ldap.FilterApproxMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
|
||||
expectedFilter: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
|
||||
expectedType: ldap.FilterEqualityMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(objectGUID=абвгдеёжзийклмнопрстуфхцчшщъыьэюя)`,
|
||||
expectedFilter: `(objectGUID=\d0\b0\d0\b1\d0\b2\d0\b3\d0\b4\d0\b5\d1\91\d0\b6\d0\b7\d0\b8\d0\b9\d0\ba\d0\bb\d0\bc\d0\bd\d0\be\d0\bf\d1\80\d1\81\d1\82\d1\83\d1\84\d1\85\d1\86\d1\87\d1\88\d1\89\d1\8a\d1\8b\d1\8c\d1\8d\d1\8e\d1\8f)`,
|
||||
expectedType: ldap.FilterEqualityMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(objectGUID=함수목록)`,
|
||||
expectedFilter: `(objectGUID=\ed\95\a8\ec\88\98\eb\aa\a9\eb\a1\9d)`,
|
||||
expectedType: ldap.FilterEqualityMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(objectGUID=`,
|
||||
expectedFilter: ``,
|
||||
expectedType: 0,
|
||||
expectedErr: "unexpected end of filter",
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(objectGUID=함수목록`,
|
||||
expectedFilter: ``,
|
||||
expectedType: 0,
|
||||
expectedErr: "unexpected end of filter",
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(&(objectclass=inetorgperson)(cn=中文))`,
|
||||
expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`,
|
||||
expectedType: 0,
|
||||
},
|
||||
// attr extension
|
||||
compileTest{
|
||||
filterStr: `(memberOf:=foo)`,
|
||||
expectedFilter: `(memberOf:=foo)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
// attr+named matching rule extension
|
||||
compileTest{
|
||||
filterStr: `(memberOf:test:=foo)`,
|
||||
expectedFilter: `(memberOf:test:=foo)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
// attr+oid matching rule extension
|
||||
compileTest{
|
||||
filterStr: `(cn:1.2.3.4.5:=Fred Flintstone)`,
|
||||
expectedFilter: `(cn:1.2.3.4.5:=Fred Flintstone)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
// attr+dn+oid matching rule extension
|
||||
compileTest{
|
||||
filterStr: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
|
||||
expectedFilter: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
// attr+dn extension
|
||||
compileTest{
|
||||
filterStr: `(o:dn:=Ace Industry)`,
|
||||
expectedFilter: `(o:dn:=Ace Industry)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
// dn extension
|
||||
compileTest{
|
||||
filterStr: `(:dn:2.4.6.8.10:=Dino)`,
|
||||
expectedFilter: `(:dn:2.4.6.8.10:=Dino)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
compileTest{
|
||||
filterStr: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
|
||||
expectedFilter: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
|
||||
expectedType: ldap.FilterExtensibleMatch,
|
||||
},
|
||||
|
||||
// compileTest{ filterStr: "()", filterType: FilterExtensibleMatch },
|
||||
}
|
||||
|
||||
var testInvalidFilters = []string{
|
||||
`(objectGUID=\zz)`,
|
||||
`(objectGUID=\a)`,
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
// Test Compiler and Decompiler
|
||||
for _, i := range testFilters {
|
||||
filter, err := ldap.CompileFilter(i.filterStr)
|
||||
if err != nil {
|
||||
if i.expectedErr == "" || !strings.Contains(err.Error(), i.expectedErr) {
|
||||
t.Errorf("Problem compiling '%s' - '%v' (expected error to contain '%v')", i.filterStr, err, i.expectedErr)
|
||||
}
|
||||
} else if filter.Tag != ber.Tag(i.expectedType) {
|
||||
t.Errorf("%q Expected %q got %q", i.filterStr, ldap.FilterMap[uint64(i.expectedType)], ldap.FilterMap[uint64(filter.Tag)])
|
||||
} else {
|
||||
o, err := ldap.DecompileFilter(filter)
|
||||
if err != nil {
|
||||
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
|
||||
} else if i.expectedFilter != o {
|
||||
t.Errorf("%q expected, got %q", i.expectedFilter, o)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidFilter(t *testing.T) {
|
||||
for _, filterStr := range testInvalidFilters {
|
||||
if _, err := ldap.CompileFilter(filterStr); err == nil {
|
||||
t.Errorf("Problem compiling %s - expected err", filterStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFilterCompile(b *testing.B) {
|
||||
b.StopTimer()
|
||||
filters := make([]string, len(testFilters))
|
||||
|
||||
// Test Compiler and Decompiler
|
||||
for idx, i := range testFilters {
|
||||
filters[idx] = i.filterStr
|
||||
}
|
||||
|
||||
maxIdx := len(filters)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ldap.CompileFilter(filters[i%maxIdx])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFilterDecompile(b *testing.B) {
|
||||
b.StopTimer()
|
||||
filters := make([]*ber.Packet, len(testFilters))
|
||||
|
||||
// Test Compiler and Decompiler
|
||||
for idx, i := range testFilters {
|
||||
filters[idx], _ = ldap.CompileFilter(i.filterStr)
|
||||
}
|
||||
|
||||
maxIdx := len(filters)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ldap.DecompileFilter(filters[i%maxIdx])
|
||||
}
|
||||
}
|
||||
275
vendor/github.com/go-ldap/ldap/ldap_test.go
generated
vendored
Normal file
275
vendor/github.com/go-ldap/ldap/ldap_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
package ldap_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
var ldapServer = "ldap.itd.umich.edu"
|
||||
var ldapPort = uint16(389)
|
||||
var ldapTLSPort = uint16(636)
|
||||
var baseDN = "dc=umich,dc=edu"
|
||||
var filter = []string{
|
||||
"(cn=cis-fac)",
|
||||
"(&(owner=*)(cn=cis-fac))",
|
||||
"(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
|
||||
"(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
|
||||
var attributes = []string{
|
||||
"cn",
|
||||
"description"}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
fmt.Printf("TestDial: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
fmt.Printf("TestDial: finished...\n")
|
||||
}
|
||||
|
||||
func TestDialTLS(t *testing.T) {
|
||||
fmt.Printf("TestDialTLS: starting...\n")
|
||||
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
fmt.Printf("TestDialTLS: finished...\n")
|
||||
}
|
||||
|
||||
func TestStartTLS(t *testing.T) {
|
||||
fmt.Printf("TestStartTLS: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("TestStartTLS: finished...\n")
|
||||
}
|
||||
|
||||
func TestSearch(t *testing.T) {
|
||||
fmt.Printf("TestSearch: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[0],
|
||||
attributes,
|
||||
nil)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||
}
|
||||
|
||||
func TestSearchStartTLS(t *testing.T) {
|
||||
fmt.Printf("TestSearchStartTLS: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[0],
|
||||
attributes,
|
||||
nil)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||
|
||||
fmt.Printf("TestSearchStartTLS: upgrading with startTLS\n")
|
||||
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sr, err = l.Search(searchRequest)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||
}
|
||||
|
||||
func TestSearchWithPaging(t *testing.T) {
|
||||
fmt.Printf("TestSearchWithPaging: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("", "")
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[2],
|
||||
attributes,
|
||||
nil)
|
||||
sr, err := l.SearchWithPaging(searchRequest, 5)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||
|
||||
searchRequest = ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[2],
|
||||
attributes,
|
||||
[]ldap.Control{ldap.NewControlPaging(5)})
|
||||
sr, err = l.SearchWithPaging(searchRequest, 5)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||
|
||||
searchRequest = ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[2],
|
||||
attributes,
|
||||
[]ldap.Control{ldap.NewControlPaging(500)})
|
||||
sr, err = l.SearchWithPaging(searchRequest, 5)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error when paging size in control in search request doesn't match size given in call, got none")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func searchGoroutine(t *testing.T, l *ldap.Conn, results chan *ldap.SearchResult, i int) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||
filter[i],
|
||||
attributes,
|
||||
nil)
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
results <- nil
|
||||
return
|
||||
}
|
||||
results <- sr
|
||||
}
|
||||
|
||||
func testMultiGoroutineSearch(t *testing.T, TLS bool, startTLS bool) {
|
||||
fmt.Printf("TestMultiGoroutineSearch: starting...\n")
|
||||
var l *ldap.Conn
|
||||
var err error
|
||||
if TLS {
|
||||
l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
} else {
|
||||
l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
if startTLS {
|
||||
fmt.Printf("TestMultiGoroutineSearch: using StartTLS...\n")
|
||||
err := l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
results := make([]chan *ldap.SearchResult, len(filter))
|
||||
for i := range filter {
|
||||
results[i] = make(chan *ldap.SearchResult)
|
||||
go searchGoroutine(t, l, results[i], i)
|
||||
}
|
||||
for i := range filter {
|
||||
sr := <-results[i]
|
||||
if sr == nil {
|
||||
t.Errorf("Did not receive results from goroutine for %q", filter[i])
|
||||
} else {
|
||||
fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiGoroutineSearch(t *testing.T) {
|
||||
testMultiGoroutineSearch(t, false, false)
|
||||
testMultiGoroutineSearch(t, true, true)
|
||||
testMultiGoroutineSearch(t, false, true)
|
||||
}
|
||||
|
||||
func TestEscapeFilter(t *testing.T) {
|
||||
if got, want := ldap.EscapeFilter("a\x00b(c)d*e\\f"), `a\00b\28c\29d\2ae\5cf`; got != want {
|
||||
t.Errorf("Got %s, expected %s", want, got)
|
||||
}
|
||||
if got, want := ldap.EscapeFilter("Lučić"), `Lu\c4\8di\c4\87`; got != want {
|
||||
t.Errorf("Got %s, expected %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompare(t *testing.T) {
|
||||
fmt.Printf("TestCompare: starting...\n")
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
dn := "cn=math mich,ou=User Groups,ou=Groups,dc=umich,dc=edu"
|
||||
attribute := "cn"
|
||||
value := "math mich"
|
||||
|
||||
sr, err := l.Compare(dn, attribute, value)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("TestCompare: -> %v\n", sr)
|
||||
}
|
||||
31
vendor/github.com/go-ldap/ldap/search_test.go
generated
vendored
Normal file
31
vendor/github.com/go-ldap/ldap/search_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package ldap
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestNewEntry tests that repeated calls to NewEntry return the same value with the same input
|
||||
func TestNewEntry(t *testing.T) {
|
||||
dn := "testDN"
|
||||
attributes := map[string][]string{
|
||||
"alpha": {"value"},
|
||||
"beta": {"value"},
|
||||
"gamma": {"value"},
|
||||
"delta": {"value"},
|
||||
"epsilon": {"value"},
|
||||
}
|
||||
exectedEntry := NewEntry(dn, attributes)
|
||||
|
||||
iteration := 0
|
||||
for {
|
||||
if iteration == 100 {
|
||||
break
|
||||
}
|
||||
testEntry := NewEntry(dn, attributes)
|
||||
if !reflect.DeepEqual(exectedEntry, testEntry) {
|
||||
t.Fatalf("consequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", exectedEntry, testEntry)
|
||||
}
|
||||
iteration = iteration + 1
|
||||
}
|
||||
}
|
||||
246
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
Normal file
246
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TB testing.B
|
||||
|
||||
func (tb *TB) check(err error) {
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB {
|
||||
tb.check(err)
|
||||
return db
|
||||
}
|
||||
|
||||
func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows {
|
||||
tb.check(err)
|
||||
return rows
|
||||
}
|
||||
|
||||
func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
|
||||
tb.check(err)
|
||||
return stmt
|
||||
}
|
||||
|
||||
func initDB(b *testing.B, queries ...string) *sql.DB {
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
for _, query := range queries {
|
||||
if _, err := db.Exec(query); err != nil {
|
||||
if w, ok := err.(MySQLWarnings); ok {
|
||||
b.Logf("warning on %q: %v", query, w)
|
||||
} else {
|
||||
b.Fatalf("error on %q: %v", query, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
const concurrencyLevel = 10
|
||||
|
||||
func BenchmarkQuery(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := initDB(b,
|
||||
"DROP TABLE IF EXISTS foo",
|
||||
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
|
||||
`INSERT INTO foo VALUES (1, "one")`,
|
||||
`INSERT INTO foo VALUES (2, "two")`,
|
||||
)
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
var got string
|
||||
tb.check(stmt.QueryRow(1).Scan(&got))
|
||||
if got != "one" {
|
||||
b.Errorf("query = %q; want one", got)
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExec(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("DO 1"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := stmt.Exec(); err != nil {
|
||||
b.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// data, but no db writes
|
||||
var roundtripSample []byte
|
||||
|
||||
func initRoundtripBenchmarks() ([]byte, int, int) {
|
||||
if roundtripSample == nil {
|
||||
roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
|
||||
}
|
||||
return roundtripSample, 16, len(roundtripSample)
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripTxt(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
sampleString := string(sample)
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
b.StartTimer()
|
||||
var result string
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sampleString[0:length]
|
||||
rows := tb.checkRows(db.Query(`SELECT "` + test + `"`))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if result != test {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripBin(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT ?"))
|
||||
defer stmt.Close()
|
||||
b.StartTimer()
|
||||
var result sql.RawBytes
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sample[0:length]
|
||||
rows := tb.checkRows(stmt.Query(test))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if !bytes.Equal(result, test) {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInterpolation(b *testing.B) {
|
||||
mc := &mysqlConn{
|
||||
cfg: &Config{
|
||||
InterpolateParams: true,
|
||||
Loc: time.UTC,
|
||||
},
|
||||
maxPacketAllowed: maxPacketSize,
|
||||
maxWriteSize: maxPacketSize - 1,
|
||||
buf: newBuffer(nil),
|
||||
}
|
||||
|
||||
args := []driver.Value{
|
||||
int64(42424242),
|
||||
float64(math.Pi),
|
||||
false,
|
||||
time.Unix(1423411542, 807015000),
|
||||
[]byte("bytes containing special chars ' \" \a \x00"),
|
||||
"string containing special chars ' \" \a \x00",
|
||||
}
|
||||
q := "SELECT ?, ?, ?, ?, ?, ?"
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := mc.interpolateParams(q, args)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
1857
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
Normal file
1857
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
207
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
Normal file
207
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testDSNs = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"username:password@protocol(address)/dbname?param=value", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:true ParseTime:false Strict:false}"},
|
||||
{"user@unix(/path/to/socket)/dbname?charset=utf8", "&{User:user Passwd: Net:unix Addr:/path/to/socket DBName:dbname Params:map[charset:utf8] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8] Collation:utf8_general_ci Loc:UTC TLSConfig:true tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8mb4,utf8] Collation:utf8_general_ci Loc:UTC TLSConfig:skip-verify tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{User:user Passwd:password Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Collation:utf8mb4_unicode_ci Loc:UTC TLSConfig: tls:<nil> Timeout:30s ReadTimeout:1s WriteTimeout:1s AllowAllFiles:true AllowCleartextPasswords:false AllowOldPasswords:true ClientFoundRows:true ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{User:user Passwd:p@ss(word) Net:tcp Addr:[de:ad:be:ef::ca:fe]:80 DBName:dbname Params:map[] Collation:utf8_general_ci Loc:Local TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"/dbname", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"@/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"user:p@/ssword@/", "&{User:user Passwd:p@/ssword Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
{"unix/?arg=%2Fsome%2Fpath.ext", "&{User: Passwd: Net:unix Addr:/tmp/mysql.sock DBName: Params:map[arg:/some/path.ext] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
||||
}
|
||||
|
||||
func TestDSNParser(t *testing.T) {
|
||||
var cfg *Config
|
||||
var err error
|
||||
var res string
|
||||
|
||||
for i, tst := range testDSNs {
|
||||
cfg, err = ParseDSN(tst.in)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
// pointer not static
|
||||
cfg.tls = nil
|
||||
|
||||
res = fmt.Sprintf("%+v", cfg)
|
||||
if res != tst.out {
|
||||
t.Errorf("%d. ParseDSN(%q) => %q, want %q", i, tst.in, res, tst.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNParserInvalid(t *testing.T) {
|
||||
var invalidDSNs = []string{
|
||||
"@net(addr/", // no closing brace
|
||||
"@tcp(/", // no closing brace
|
||||
"tcp(/", // no closing brace
|
||||
"(/", // no closing brace
|
||||
"net(addr)//", // unescaped
|
||||
"User:pass@tcp(1.2.3.4:3306)", // no trailing slash
|
||||
//"/dbname?arg=/some/unescaped/path",
|
||||
}
|
||||
|
||||
for i, tst := range invalidDSNs {
|
||||
if _, err := ParseDSN(tst); err == nil {
|
||||
t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNReformat(t *testing.T) {
|
||||
for i, tst := range testDSNs {
|
||||
dsn1 := tst.in
|
||||
cfg1, err := ParseDSN(dsn1)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
cfg1.tls = nil // pointer not static
|
||||
res1 := fmt.Sprintf("%+v", cfg1)
|
||||
|
||||
dsn2 := cfg1.FormatDSN()
|
||||
cfg2, err := ParseDSN(dsn2)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
cfg2.tls = nil // pointer not static
|
||||
res2 := fmt.Sprintf("%+v", cfg2)
|
||||
|
||||
if res1 != res2 {
|
||||
t.Errorf("%d. %q does not match %q", i, res2, res1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNWithCustomTLS(t *testing.T) {
|
||||
baseDSN := "User:password@tcp(localhost:5555)/dbname?tls="
|
||||
tlsCfg := tls.Config{}
|
||||
|
||||
RegisterTLSConfig("utils_test", &tlsCfg)
|
||||
|
||||
// Custom TLS is missing
|
||||
tst := baseDSN + "invalid_tls"
|
||||
cfg, err := ParseDSN(tst)
|
||||
if err == nil {
|
||||
t.Errorf("invalid custom TLS in DSN (%s) but did not error. Got config: %#v", tst, cfg)
|
||||
}
|
||||
|
||||
tst = baseDSN + "utils_test"
|
||||
|
||||
// Custom TLS with a server name
|
||||
name := "foohost"
|
||||
tlsCfg.ServerName = name
|
||||
cfg, err = ParseDSN(tst)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, tst)
|
||||
}
|
||||
|
||||
// Custom TLS without a server name
|
||||
name = "localhost"
|
||||
tlsCfg.ServerName = ""
|
||||
cfg, err = ParseDSN(tst)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst)
|
||||
}
|
||||
|
||||
DeregisterTLSConfig("utils_test")
|
||||
}
|
||||
|
||||
func TestDSNWithCustomTLSQueryEscape(t *testing.T) {
|
||||
const configKey = "&%!:"
|
||||
dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey)
|
||||
name := "foohost"
|
||||
tlsCfg := tls.Config{ServerName: name}
|
||||
|
||||
RegisterTLSConfig(configKey, &tlsCfg)
|
||||
|
||||
cfg, err := ParseDSN(dsn)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, dsn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNUnsafeCollation(t *testing.T) {
|
||||
_, err := ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=true")
|
||||
if err != errInvalidDSNUnsafeCollation {
|
||||
t.Errorf("expected %v, got %v", errInvalidDSNUnsafeCollation, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=false")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=gbk_chinese_ci")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=ascii_bin&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=latin1_german1_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=utf8_general_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=utf8mb4_general_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseDSN(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tst := range testDSNs {
|
||||
if _, err := ParseDSN(tst.in); err != nil {
|
||||
b.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
vendor/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
Normal file
42
vendor/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorsSetLogger(t *testing.T) {
|
||||
previous := errLog
|
||||
defer func() {
|
||||
errLog = previous
|
||||
}()
|
||||
|
||||
// set up logger
|
||||
const expected = "prefix: test\n"
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 64))
|
||||
logger := log.New(buffer, "prefix: ", 0)
|
||||
|
||||
// print
|
||||
SetLogger(logger)
|
||||
errLog.Print("test")
|
||||
|
||||
// check result
|
||||
if actual := buffer.String(); actual != expected {
|
||||
t.Errorf("expected %q, got %q", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsStrictIgnoreNotes(t *testing.T) {
|
||||
runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) {
|
||||
dbt.mustExec("DROP TABLE IF EXISTS does_not_exist")
|
||||
})
|
||||
}
|
||||
197
vendor/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
Normal file
197
vendor/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestScanNullTime(t *testing.T) {
|
||||
var scanTests = []struct {
|
||||
in interface{}
|
||||
error bool
|
||||
valid bool
|
||||
time time.Time
|
||||
}{
|
||||
{tDate, false, true, tDate},
|
||||
{sDate, false, true, tDate},
|
||||
{[]byte(sDate), false, true, tDate},
|
||||
{tDateTime, false, true, tDateTime},
|
||||
{sDateTime, false, true, tDateTime},
|
||||
{[]byte(sDateTime), false, true, tDateTime},
|
||||
{tDate0, false, true, tDate0},
|
||||
{sDate0, false, true, tDate0},
|
||||
{[]byte(sDate0), false, true, tDate0},
|
||||
{sDateTime0, false, true, tDate0},
|
||||
{[]byte(sDateTime0), false, true, tDate0},
|
||||
{"", true, false, tDate0},
|
||||
{"1234", true, false, tDate0},
|
||||
{0, true, false, tDate0},
|
||||
}
|
||||
|
||||
var nt = NullTime{}
|
||||
var err error
|
||||
|
||||
for _, tst := range scanTests {
|
||||
err = nt.Scan(tst.in)
|
||||
if (err != nil) != tst.error {
|
||||
t.Errorf("%v: expected error status %t, got %t", tst.in, tst.error, (err != nil))
|
||||
}
|
||||
if nt.Valid != tst.valid {
|
||||
t.Errorf("%v: expected valid status %t, got %t", tst.in, tst.valid, nt.Valid)
|
||||
}
|
||||
if nt.Time != tst.time {
|
||||
t.Errorf("%v: expected time %v, got %v", tst.in, tst.time, nt.Time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLengthEncodedInteger(t *testing.T) {
|
||||
var integerTests = []struct {
|
||||
num uint64
|
||||
encoded []byte
|
||||
}{
|
||||
{0x0000000000000000, []byte{0x00}},
|
||||
{0x0000000000000012, []byte{0x12}},
|
||||
{0x00000000000000fa, []byte{0xfa}},
|
||||
{0x0000000000000100, []byte{0xfc, 0x00, 0x01}},
|
||||
{0x0000000000001234, []byte{0xfc, 0x34, 0x12}},
|
||||
{0x000000000000ffff, []byte{0xfc, 0xff, 0xff}},
|
||||
{0x0000000000010000, []byte{0xfd, 0x00, 0x00, 0x01}},
|
||||
{0x0000000000123456, []byte{0xfd, 0x56, 0x34, 0x12}},
|
||||
{0x0000000000ffffff, []byte{0xfd, 0xff, 0xff, 0xff}},
|
||||
{0x0000000001000000, []byte{0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}},
|
||||
{0x123456789abcdef0, []byte{0xfe, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}},
|
||||
{0xffffffffffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
|
||||
}
|
||||
|
||||
for _, tst := range integerTests {
|
||||
num, isNull, numLen := readLengthEncodedInteger(tst.encoded)
|
||||
if isNull {
|
||||
t.Errorf("%x: expected %d, got NULL", tst.encoded, tst.num)
|
||||
}
|
||||
if num != tst.num {
|
||||
t.Errorf("%x: expected %d, got %d", tst.encoded, tst.num, num)
|
||||
}
|
||||
if numLen != len(tst.encoded) {
|
||||
t.Errorf("%x: expected size %d, got %d", tst.encoded, len(tst.encoded), numLen)
|
||||
}
|
||||
encoded := appendLengthEncodedInteger(nil, num)
|
||||
if !bytes.Equal(encoded, tst.encoded) {
|
||||
t.Errorf("%v: expected %x, got %x", num, tst.encoded, encoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldPass(t *testing.T) {
|
||||
scramble := []byte{9, 8, 7, 6, 5, 4, 3, 2}
|
||||
vectors := []struct {
|
||||
pass string
|
||||
out string
|
||||
}{
|
||||
{" pass", "47575c5a435b4251"},
|
||||
{"pass ", "47575c5a435b4251"},
|
||||
{"123\t456", "575c47505b5b5559"},
|
||||
{"C0mpl!ca ted#PASS123", "5d5d554849584a45"},
|
||||
}
|
||||
for _, tuple := range vectors {
|
||||
ours := scrambleOldPassword(scramble, []byte(tuple.pass))
|
||||
if tuple.out != fmt.Sprintf("%x", ours) {
|
||||
t.Errorf("Failed old password %q", tuple.pass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatBinaryDateTime(t *testing.T) {
|
||||
rawDate := [11]byte{}
|
||||
binary.LittleEndian.PutUint16(rawDate[:2], 1978) // years
|
||||
rawDate[2] = 12 // months
|
||||
rawDate[3] = 30 // days
|
||||
rawDate[4] = 15 // hours
|
||||
rawDate[5] = 46 // minutes
|
||||
rawDate[6] = 23 // seconds
|
||||
binary.LittleEndian.PutUint32(rawDate[7:], 987654) // microseconds
|
||||
expect := func(expected string, inlen, outlen uint8) {
|
||||
actual, _ := formatBinaryDateTime(rawDate[:inlen], outlen, false)
|
||||
bytes, ok := actual.([]byte)
|
||||
if !ok {
|
||||
t.Errorf("formatBinaryDateTime must return []byte, was %T", actual)
|
||||
}
|
||||
if string(bytes) != expected {
|
||||
t.Errorf(
|
||||
"expected %q, got %q for length in %d, out %d",
|
||||
bytes, actual, inlen, outlen,
|
||||
)
|
||||
}
|
||||
}
|
||||
expect("0000-00-00", 0, 10)
|
||||
expect("0000-00-00 00:00:00", 0, 19)
|
||||
expect("1978-12-30", 4, 10)
|
||||
expect("1978-12-30 15:46:23", 7, 19)
|
||||
expect("1978-12-30 15:46:23.987654", 11, 26)
|
||||
}
|
||||
|
||||
func TestEscapeBackslash(t *testing.T) {
|
||||
expect := func(expected, value string) {
|
||||
actual := string(escapeBytesBackslash([]byte{}, []byte(value)))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
|
||||
actual = string(escapeStringBackslash([]byte{}, value))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
expect("foo\\0bar", "foo\x00bar")
|
||||
expect("foo\\nbar", "foo\nbar")
|
||||
expect("foo\\rbar", "foo\rbar")
|
||||
expect("foo\\Zbar", "foo\x1abar")
|
||||
expect("foo\\\"bar", "foo\"bar")
|
||||
expect("foo\\\\bar", "foo\\bar")
|
||||
expect("foo\\'bar", "foo'bar")
|
||||
}
|
||||
|
||||
func TestEscapeQuotes(t *testing.T) {
|
||||
expect := func(expected, value string) {
|
||||
actual := string(escapeBytesQuotes([]byte{}, []byte(value)))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
|
||||
actual = string(escapeStringQuotes([]byte{}, value))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
expect("foo\x00bar", "foo\x00bar") // not affected
|
||||
expect("foo\nbar", "foo\nbar") // not affected
|
||||
expect("foo\rbar", "foo\rbar") // not affected
|
||||
expect("foo\x1abar", "foo\x1abar") // not affected
|
||||
expect("foo''bar", "foo'bar") // affected
|
||||
expect("foo\"bar", "foo\"bar") // not affected
|
||||
}
|
||||
1
vendor/github.com/goamz/goamz/.gitignore
generated
vendored
Normal file
1
vendor/github.com/goamz/goamz/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
*.swp
|
||||
1
vendor/github.com/goamz/goamz/.lbox
generated
vendored
Normal file
1
vendor/github.com/goamz/goamz/.lbox
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
propose -for=lp:goamz -cr
|
||||
32
vendor/github.com/goamz/goamz/.travis.yml
generated
vendored
Normal file
32
vendor/github.com/goamz/goamz/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- tip
|
||||
|
||||
before_script:
|
||||
- FIXED=$(go fmt ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "gofmt - $FIXED file(s) not formatted correctly, please run gofmt to fix this." && exit 1; fi
|
||||
|
||||
script:
|
||||
- go test -v ./autoscaling/
|
||||
- go test -v ./aws/
|
||||
- go test -v ./cloudformation/
|
||||
- go test -v ./cloudfront/
|
||||
- go test -v ./cloudwatch/
|
||||
- go test -v ./dynamodb/
|
||||
- go test -v ./ec2/
|
||||
- go test -v ./ecs/
|
||||
- go test -v ./elb/
|
||||
- go test -v ./iam/
|
||||
- go test -v ./rds/
|
||||
- go test -v ./route53/
|
||||
- go test -v ./s3/
|
||||
- go test -v ./sqs/
|
||||
- go test -v ./sts/
|
||||
- go test -v ./exp/mturk/
|
||||
- go test -v ./exp/sdb/
|
||||
# - go test -v ./exp/ses/
|
||||
# - go test -v ./exp/sns/
|
||||
5
vendor/github.com/goamz/goamz/CHANGES.md
generated
vendored
Normal file
5
vendor/github.com/goamz/goamz/CHANGES.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Changes in this fork
|
||||
|
||||
* Added CNNorth Region
|
||||
* Change SignV2 to SignV4
|
||||
* V4Signer.canonicalQueryString empty value must append "="
|
||||
64
vendor/github.com/goamz/goamz/README.md
generated
vendored
Normal file
64
vendor/github.com/goamz/goamz/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# goamz - An Amazon Library for Go
|
||||
|
||||
[](https://travis-ci.org/goamz/goamz)
|
||||
|
||||
The _goamz_ package enables Go programs to interact with Amazon Web Services.
|
||||
|
||||
This is a fork of the version [developed within Canonical](https://wiki.ubuntu.com/goamz) with additional functionality and services from [a number of contributors](https://github.com/goamz/goamz/contributors)!
|
||||
|
||||
The API of AWS is very comprehensive, though, and goamz doesn't even scratch the surface of it. That said, it's fairly well tested, and is the foundation in which further calls can easily be integrated. We'll continue extending the API as necessary - Pull Requests are _very_ welcome!
|
||||
|
||||
The following packages are available at the moment:
|
||||
|
||||
```
|
||||
github.com/goamz/goamz/autoscaling
|
||||
github.com/goamz/goamz/aws
|
||||
github.com/goamz/goamz/cloudformation
|
||||
github.com/goamz/goamz/cloudfront
|
||||
github.com/goamz/goamz/cloudwatch
|
||||
github.com/goamz/goamz/dynamodb
|
||||
github.com/goamz/goamz/ecs
|
||||
github.com/goamz/goamz/ec2
|
||||
github.com/goamz/goamz/elb
|
||||
github.com/goamz/goamz/iam
|
||||
github.com/goamz/goamz/rds
|
||||
github.com/goamz/goamz/route53
|
||||
github.com/goamz/goamz/s3
|
||||
github.com/goamz/goamz/sqs
|
||||
github.com/goamz/goamz/sts
|
||||
|
||||
github.com/goamz/goamz/exp/mturk
|
||||
github.com/goamz/goamz/exp/sdb
|
||||
github.com/goamz/goamz/exp/sns
|
||||
```
|
||||
|
||||
Packages under `exp/` are still in an experimental or unfinished/unpolished state.
|
||||
|
||||
## API documentation
|
||||
|
||||
The API documentation is currently available at:
|
||||
|
||||
[http://godoc.org/github.com/goamz/goamz](http://godoc.org/github.com/goamz/goamz)
|
||||
|
||||
## How to build and install goamz
|
||||
|
||||
Just use `go get` with any of the available packages. For example:
|
||||
|
||||
* `$ go get github.com/goamz/goamz/ec2`
|
||||
* `$ go get github.com/goamz/goamz/s3`
|
||||
|
||||
## Running tests
|
||||
|
||||
To run tests, first install gocheck with:
|
||||
|
||||
`$ go get gopkg.in/check.v1`
|
||||
|
||||
Then run go test as usual:
|
||||
|
||||
`$ go test github.com/goamz/goamz/...`
|
||||
|
||||
_Note:_ running all tests with the command `go test ./...` will currently fail as tests do not tear down their HTTP listeners.
|
||||
|
||||
If you want to run integration tests (costs money), set up the EC2 environment variables as usual, and run:
|
||||
|
||||
$ gotest -i
|
||||
1768
vendor/github.com/goamz/goamz/autoscaling/autoscaling.go
generated
vendored
Normal file
1768
vendor/github.com/goamz/goamz/autoscaling/autoscaling.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1180
vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go
generated
vendored
Normal file
1180
vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
627
vendor/github.com/goamz/goamz/autoscaling/responses_test.go
generated
vendored
Normal file
627
vendor/github.com/goamz/goamz/autoscaling/responses_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
package autoscaling
|
||||
|
||||
var AttachInstancesResponse = `
|
||||
<AttachInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</AttachInstancesResponse>
|
||||
`
|
||||
var BasicGroupResponse = `
|
||||
<DescribeAutoScalingGroupsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeAutoScalingGroupsResult>
|
||||
<AutoScalingGroups/>
|
||||
</DescribeAutoScalingGroupsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>08c3bedc-8421-11e3-9bb5-bfa219b29cce</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeAutoScalingGroupsResponse>
|
||||
`
|
||||
var CreateAutoScalingGroupResponse = `
|
||||
<CreateAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateAutoScalingGroupResponse>
|
||||
`
|
||||
var CreateLaunchConfigurationResponse = `
|
||||
<CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateLaunchConfigurationResponse>
|
||||
`
|
||||
var CreateOrUpdateTagsResponse = `
|
||||
<CreateOrUpdateTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>b0203919-bf1b-11e2-8a01-13263EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateOrUpdateTagsResponse>
|
||||
`
|
||||
var DeleteAutoScalingGroupResponse = `
|
||||
<DeleteAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DeleteAutoScalingGroupResponse>
|
||||
`
|
||||
var DeleteAutoScalingGroupErrorResponse = `
|
||||
<ErrorResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<Error>
|
||||
<Type>Sender</Type>
|
||||
<Code>ResourceInUse</Code>
|
||||
<Message>You cannot delete an AutoScalingGroup while there are instances or pending Spot instance request(s) still in the group.</Message>
|
||||
</Error>
|
||||
<RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
|
||||
</ErrorResponse>
|
||||
`
|
||||
var DeleteLaunchConfigurationResponse = `
|
||||
<DeleteLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>7347261f-97df-11e2-8756-35eEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DeleteLaunchConfigurationResponse>
|
||||
`
|
||||
var DeleteLaunchConfigurationInUseResponse = `
|
||||
<ErrorResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<Error>
|
||||
<Type>Sender</Type>
|
||||
<Code>ResourceInUse</Code>
|
||||
<Message>Cannot delete launch configuration my-test-lc because it is attached to AutoScalingGroup test</Message>
|
||||
</Error>
|
||||
<RequestId>7347261f-97df-11e2-8756-35eEXAMPLE</RequestId>
|
||||
</ErrorResponse>
|
||||
`
|
||||
var DeleteScheduledActionResponse = `
|
||||
<DeleteScheduledActionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>0f38bb02-8421-11e3-9bb5-bfa219b29cce</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DeleteScheduledActionResponse>
|
||||
`
|
||||
var DeleteTagsResponse = `
|
||||
<CreateOrUpdateTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>b0203919-bf1b-11e2-8a01-13263EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateOrUpdateTagsResponse>
|
||||
`
|
||||
var DescribeAccountLimitsResponse = `
|
||||
<DescribeAccountLimitsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeAccountLimitsResult>
|
||||
<MaxNumberOfLaunchConfigurations>100</MaxNumberOfLaunchConfigurations>
|
||||
<MaxNumberOfAutoScalingGroups>20</MaxNumberOfAutoScalingGroups>
|
||||
</DescribeAccountLimitsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>a32bd184-519d-11e3-a8a4-c1c467cbcc3b</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeAccountLimitsResponse>
|
||||
`
|
||||
var DescribeAdjustmentTypesResponse = `
|
||||
<DescribeAdjustmentTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/201-01-01/">
|
||||
<DescribeAdjustmentTypesResult>
|
||||
<AdjustmentTypes>
|
||||
<member>
|
||||
<AdjustmentType>ChangeInCapacity</AdjustmentType>
|
||||
</member>
|
||||
<member>
|
||||
<AdjustmentType>ExactCapacity</AdjustmentType>
|
||||
</member>
|
||||
<member>
|
||||
<AdjustmentType>PercentChangeInCapacity</AdjustmentType>
|
||||
</member>
|
||||
</AdjustmentTypes>
|
||||
</DescribeAdjustmentTypesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>cc5f0337-b694-11e2-afc0-6544dEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeAdjustmentTypesResponse>
|
||||
`
|
||||
var DescribeAutoScalingGroupsResponse = `
|
||||
<DescribeAutoScalingGroupsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeAutoScalingGroupsResult>
|
||||
<AutoScalingGroups>
|
||||
<member>
|
||||
<Tags>
|
||||
<member>
|
||||
<ResourceId>my-test-asg-lbs</ResourceId>
|
||||
<PropagateAtLaunch>true</PropagateAtLaunch>
|
||||
<Value>bar</Value>
|
||||
<Key>foo</Key>
|
||||
<ResourceType>auto-scaling-group</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceId>my-test-asg-lbs</ResourceId>
|
||||
<PropagateAtLaunch>true</PropagateAtLaunch>
|
||||
<Value>qux</Value>
|
||||
<Key>baz</Key>
|
||||
<ResourceType>auto-scaling-group</ResourceType>
|
||||
</member>
|
||||
</Tags>
|
||||
<SuspendedProcesses/>
|
||||
<AutoScalingGroupName>my-test-asg-lbs</AutoScalingGroupName>
|
||||
<HealthCheckType>ELB</HealthCheckType>
|
||||
<CreatedTime>2013-05-06T17:47:15.107Z</CreatedTime>
|
||||
<EnabledMetrics/>
|
||||
<LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
|
||||
<Instances>
|
||||
<member>
|
||||
<HealthStatus>Healthy</HealthStatus>
|
||||
<AvailabilityZone>us-east-1b</AvailabilityZone>
|
||||
<InstanceId>i-zb1f313</InstanceId>
|
||||
<LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
|
||||
<LifecycleState>InService</LifecycleState>
|
||||
</member>
|
||||
<member>
|
||||
<HealthStatus>Healthy</HealthStatus>
|
||||
<AvailabilityZone>us-east-1a</AvailabilityZone>
|
||||
<InstanceId>i-90123adv</InstanceId>
|
||||
<LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
|
||||
<LifecycleState>InService</LifecycleState>
|
||||
</member>
|
||||
</Instances>
|
||||
<DesiredCapacity>2</DesiredCapacity>
|
||||
<AvailabilityZones>
|
||||
<member>us-east-1b</member>
|
||||
<member>us-east-1a</member>
|
||||
</AvailabilityZones>
|
||||
<LoadBalancerNames>
|
||||
<member>my-test-asg-loadbalancer</member>
|
||||
</LoadBalancerNames>
|
||||
<MinSize>2</MinSize>
|
||||
<VPCZoneIdentifier>subnet-32131da1,subnet-1312dad2</VPCZoneIdentifier>
|
||||
<HealthCheckGracePeriod>120</HealthCheckGracePeriod>
|
||||
<DefaultCooldown>300</DefaultCooldown>
|
||||
<AutoScalingGroupARN>arn:aws:autoscaling:us-east-1:803981987763:autoScalingGroup:ca861182-c8f9-4ca7-b1eb-cd35505f5ebb:autoScalingGroupName/my-test-asg-lbs</AutoScalingGroupARN>
|
||||
<TerminationPolicies>
|
||||
<member>Default</member>
|
||||
</TerminationPolicies>
|
||||
<MaxSize>10</MaxSize>
|
||||
</member>
|
||||
</AutoScalingGroups>
|
||||
</DescribeAutoScalingGroupsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>0f02a07d-b677-11e2-9eb0-dd50EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeAutoScalingGroupsResponse>
|
||||
`
|
||||
var DescribeAutoScalingInstancesResponse = `
|
||||
<DescribeAutoScalingInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeAutoScalingInstancesResult>
|
||||
<AutoScalingInstances>
|
||||
<member>
|
||||
<HealthStatus>Healthy</HealthStatus>
|
||||
<AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
|
||||
<AvailabilityZone>us-east-1a</AvailabilityZone>
|
||||
<InstanceId>i-78e0d40b</InstanceId>
|
||||
<LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
|
||||
<LifecycleState>InService</LifecycleState>
|
||||
</member>
|
||||
</AutoScalingInstances>
|
||||
</DescribeAutoScalingInstancesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>df992dc3-b72f-11e2-81e1-750aa6EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeAutoScalingInstancesResponse>
|
||||
`
|
||||
var DescribeLaunchConfigurationsResponse = `
|
||||
<DescribeLaunchConfigurationsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeLaunchConfigurationsResult>
|
||||
<LaunchConfigurations>
|
||||
<member>
|
||||
<AssociatePublicIpAddress>true</AssociatePublicIpAddress>
|
||||
<SecurityGroups/>
|
||||
<CreatedTime>2013-01-21T23:04:42.200Z</CreatedTime>
|
||||
<KernelId/>
|
||||
<LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
|
||||
<UserData/>
|
||||
<InstanceType>m1.small</InstanceType>
|
||||
<LaunchConfigurationARN>arn:aws:autoscaling:us-east-1:803981987763:launchConfiguration:9dbbbf87-6141-428a-a409-0752edbe6cad:launchConfigurationName/my-test-lc</LaunchConfigurationARN>
|
||||
<BlockDeviceMappings>
|
||||
<member>
|
||||
<VirtualName>ephemeral0</VirtualName>
|
||||
<DeviceName>/dev/sdb</DeviceName>
|
||||
</member>
|
||||
<member>
|
||||
<Ebs>
|
||||
<SnapshotId>snap-XXXXYYY</SnapshotId>
|
||||
<VolumeSize>100</VolumeSize>
|
||||
<Iops>50</Iops>
|
||||
<VolumeType>io1</VolumeType>
|
||||
<DeleteOnTermination>true</DeleteOnTermination>
|
||||
</Ebs>
|
||||
<DeviceName>/dev/sdf</DeviceName>
|
||||
</member>
|
||||
</BlockDeviceMappings>
|
||||
<ImageId>ami-514ac838</ImageId>
|
||||
<KeyName/>
|
||||
<RamdiskId/>
|
||||
<InstanceMonitoring>
|
||||
<Enabled>true</Enabled>
|
||||
</InstanceMonitoring>
|
||||
<EbsOptimized>false</EbsOptimized>
|
||||
</member>
|
||||
</LaunchConfigurations>
|
||||
</DescribeLaunchConfigurationsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>d05a22f8-b690-11e2-bf8e-2113fEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeLaunchConfigurationsResponse>
|
||||
`
|
||||
var DescribeMetricCollectionTypesResponse = `
|
||||
<DescribeMetricCollectionTypesResponse xmlns="http://autoscaling.amazonaws.co
|
||||
oc/2011-01-01/">
|
||||
<DescribeMetricCollectionTypesResult>
|
||||
<Metrics>
|
||||
<member>
|
||||
<Metric>GroupMinSize</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupMaxSize</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupDesiredCapacity</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupInServiceInstances</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupPendingInstances</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupTerminatingInstances</Metric>
|
||||
</member>
|
||||
<member>
|
||||
<Metric>GroupTotalInstances</Metric>
|
||||
</member>
|
||||
</Metrics>
|
||||
<Granularities>
|
||||
<member>
|
||||
<Granularity>1Minute</Granularity>
|
||||
</member>
|
||||
</Granularities>
|
||||
</DescribeMetricCollectionTypesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeMetricCollectionTypesResponse>
|
||||
`
|
||||
var DescribeNotificationConfigurationsResponse = `
|
||||
<DescribeNotificationConfigurationsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeNotificationConfigurationsResult>
|
||||
<NotificationConfigurations>
|
||||
<member>
|
||||
<AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
|
||||
<NotificationType>autoscaling: EC2_INSTANCE_LAUNCH</NotificationType>
|
||||
<TopicARN>vajdoafj231j41231/topic</TopicARN>
|
||||
</member>
|
||||
</NotificationConfigurations>
|
||||
</DescribeNotificationConfigurationsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeNotificationConfigurationsResponse>
|
||||
`
|
||||
var DescribePoliciesResponse = `
|
||||
<DescribePoliciesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribePoliciesResult>
|
||||
<NextToken>3ef417fe-9202-12-8ddd-d13e1313413</NextToken>
|
||||
<ScalingPolicies>
|
||||
<member>
|
||||
<PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/my-test-asg:policyName/MyScaleDownPolicy</PolicyARN>
|
||||
<AdjustmentType>ChangeInCapacity</AdjustmentType>
|
||||
<ScalingAdjustment>-1</ScalingAdjustment>
|
||||
<PolicyName>MyScaleDownPolicy</PolicyName>
|
||||
<AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
|
||||
<Cooldown>60</Cooldown>
|
||||
<Alarms>
|
||||
<member>
|
||||
<AlarmName>TestQueue</AlarmName>
|
||||
<AlarmARN>arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue</AlarmARN>
|
||||
</member>
|
||||
</Alarms>
|
||||
</member>
|
||||
<member>
|
||||
<PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c55a5cdd-9be0-435b-b60b-a8dd313159f5:autoScalingGroupName/my-test-asg:policyName/MyScaleUpPolicy</PolicyARN>
|
||||
<AdjustmentType>ChangeInCapacity</AdjustmentType>
|
||||
<ScalingAdjustment>1</ScalingAdjustment>
|
||||
<PolicyName>MyScaleUpPolicy</PolicyName>
|
||||
<AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
|
||||
<Cooldown>60</Cooldown>
|
||||
<Alarms>
|
||||
<member>
|
||||
<AlarmName>TestQueue</AlarmName>
|
||||
<AlarmARN>arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue</AlarmARN>
|
||||
</member>
|
||||
</Alarms>
|
||||
</member>
|
||||
</ScalingPolicies>
|
||||
</DescribePoliciesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>ec3bffad-b739-11e2-b38d-15fbEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribePoliciesResponse>
|
||||
`
|
||||
var DescribeScalingActivitiesResponse = `
|
||||
<DescribeScalingActivitiesResponse xmlns="http://ec2.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeScalingActivitiesResult>
|
||||
<NextToken>3ef417fe-9202-12-8ddd-d13e1313413</NextToken>
|
||||
<Activities>
|
||||
<member>
|
||||
<StatusCode>Failed</StatusCode>
|
||||
<Progress>0</Progress>
|
||||
<ActivityId>063308ae-aa22-4a9b-94f4-9faeEXAMPLE</ActivityId>
|
||||
<StartTime>2012-04-12T17:32:07.882Z</StartTime>
|
||||
<AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
|
||||
<Cause>At 2012-04-12T17:31:30Z a user request created an AutoScalingGroup changing the desired capacity from 0 to 1. At 2012-04-12T17:32:07Z an instance was started in response to a difference between desired and actual capacity, increasing the capacity from 0 to 1.</Cause>
|
||||
<Details>{}</Details>
|
||||
<Description>Launching a new EC2 instance. Status Reason: The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.</Description>
|
||||
<EndTime>2012-04-12T17:32:08Z</EndTime>
|
||||
<StatusMessage>The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.</StatusMessage>
|
||||
</member>
|
||||
</Activities>
|
||||
</DescribeScalingActivitiesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>7a641adc-84c5-11e1-a8a5-217ebEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeScalingActivitiesResponse>
|
||||
`
|
||||
var DescribeScalingProcessTypesResponse = `
|
||||
<DescribeScalingProcessTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeScalingProcessTypesResult>
|
||||
<Processes>
|
||||
<member>
|
||||
<ProcessName>AZRebalance</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>AddToLoadBalancer</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>AlarmNotification</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>HealthCheck</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>Launch</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>ReplaceUnhealthy</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>ScheduledActions</ProcessName>
|
||||
</member>
|
||||
<member>
|
||||
<ProcessName>Terminate</ProcessName>
|
||||
</member>
|
||||
</Processes>
|
||||
</DescribeScalingProcessTypesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>27f2eacc-b73f-11e2-ad99-c7aba3a9c963</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeScalingProcessTypesResponse>
|
||||
`
|
||||
var DescribeScheduledActionsResponse = `
|
||||
<DescribeScheduledActionsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeScheduledActionsResult>
|
||||
<ScheduledUpdateGroupActions>
|
||||
<member>
|
||||
<ScheduledActionName>SATest1</ScheduledActionName>
|
||||
<StartTime>2014-06-01T00:30:00Z</StartTime>
|
||||
<Time>2014-06-01T00:30:00Z</Time>
|
||||
<ScheduledActionARN>arn:aws:autoscaling:us-west-2:193024542802:scheduledUpdateGroupAction:61f68b2c-bde3-4316-9a81-eb95dc246509:autoScalingGroupName/ASGTest1:scheduledActionName/SATest1</ScheduledActionARN>
|
||||
<AutoScalingGroupName>ASGTest1</AutoScalingGroupName>
|
||||
<Recurrence>30 0 1 1,6,12 *</Recurrence>
|
||||
<MaxSize>4</MaxSize>
|
||||
</member>
|
||||
</ScheduledUpdateGroupActions>
|
||||
</DescribeScheduledActionsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>0eb4217f-8421-11e3-9233-7100ef811766</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeScheduledActionsResponse>
|
||||
`
|
||||
|
||||
var DescribeTerminationPolicyTypesResponse = `
|
||||
<DescribeTerminationPolicyTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeTerminationPolicyTypesResult>
|
||||
<TerminationPolicyTypes>
|
||||
<member>ClosestToNextInstanceHour</member>
|
||||
<member>Default</member>
|
||||
<member>NewestInstance</member>
|
||||
<member>OldestInstance</member>
|
||||
<member>OldestLaunchConfiguration</member>
|
||||
</TerminationPolicyTypes>
|
||||
</DescribeTerminationPolicyTypesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>d9a05827-b735-11e2-a40c-c79a5EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeTerminationPolicyTypesResponse>
|
||||
`
|
||||
var DescribeTagsResponse = `
|
||||
<DescribeTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DescribeTagsResult>
|
||||
<Tags>
|
||||
<member>
|
||||
<ResourceId>my-test-asg</ResourceId>
|
||||
<PropagateAtLaunch>true</PropagateAtLaunch>
|
||||
<Value>1.0</Value>
|
||||
<Key>version</Key>
|
||||
<ResourceType>auto-scaling-group</ResourceType>
|
||||
</member>
|
||||
</Tags>
|
||||
</DescribeTagsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>086265fd-bf3e-11e2-85fc-fbb1EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeTagsResponse>
|
||||
`
|
||||
var DetachInstancesResponse = `
|
||||
<DetachInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<DetachInstancesResult>
|
||||
<Activities>
|
||||
<member>
|
||||
<ActivityId>e54ff599-bf05-4076-8b95-a0f090ed90bb</ActivityId>
|
||||
<Progress>50</Progress>
|
||||
<StatusCode>InProgress</StatusCode>
|
||||
<StartTime>2014-06-14T00:07:30.280Z</StartTime>
|
||||
<Cause>At 2014-06-14T00:07:30Z instance i-5f2e8a0d was detached in response to a user request, shrinking the capacity from 4 to 3.</Cause>
|
||||
<AutoScalingGroupName>my-asg</AutoScalingGroupName>
|
||||
<Details>{"Availability Zone":"us-east-1a"}</Details>
|
||||
<Description>Detaching EC2 instance: i-5f2e8a0d</Description>
|
||||
</member>
|
||||
</Activities>
|
||||
</DetachInstancesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>e04f3b11-f357-11e3-a434-7f10009d5849</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DetachInstancesResponse>
|
||||
`
|
||||
var DisableMetricsCollectionResponse = `
|
||||
<DisableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DisableMetricsCollectionResponse>
|
||||
`
|
||||
var EnableMetricsCollectionResponse = `
|
||||
<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</EnableMetricsCollectionResponse>
|
||||
`
|
||||
var EnterStandbyResponse = `
|
||||
<EnterStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<EnterStandbyResult>
|
||||
<Activities>
|
||||
<member>
|
||||
<ActivityId>462b4bc3-ad3b-4e67-a58d-96cd00f02f9e</ActivityId>
|
||||
<Progress>50</Progress>
|
||||
<StatusCode>InProgress</StatusCode>
|
||||
<StartTime>2014-06-13T22:35:50.884Z</StartTime>
|
||||
<Cause>At 2014-06-13T22:35:50Z instance i-5b73d709 was moved to standby in response to a user request, shrinking the capacity from 4 to 3.</Cause>
|
||||
<AutoScalingGroupName>my-asg</AutoScalingGroupName>
|
||||
<Details>{"Availability Zone":"us-east-1a"}</Details>
|
||||
<Description>Moving EC2 instance to Standby: i-5b73d709</Description>
|
||||
</member>
|
||||
</Activities>
|
||||
</EnterStandbyResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>126f2f31-f34b-11e3-bc51-b35178f0274f</RequestId>
|
||||
</ResponseMetadata>
|
||||
</EnterStandbyResponse>
|
||||
`
|
||||
var ExecutePolicyResponse = `
|
||||
<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</EnableMetricsCollectionResponse>
|
||||
`
|
||||
var ExitStandbyResponse = `
|
||||
<ExitStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ExitStandbyResult>
|
||||
<Activities>
|
||||
<member>
|
||||
<ActivityId>dca4efcf-eea6-4844-8064-cab1fecd1aa2</ActivityId>
|
||||
<Progress>30</Progress>
|
||||
<StatusCode>PreInService</StatusCode>
|
||||
<StartTime>2014-06-13T22:43:53.523Z</StartTime>
|
||||
<Cause>At 2014-06-13T22:43:53Z instance i-5b73d709 was moved out of standby in response to a user request, increasing the capacity from 3 to 4.</Cause>
|
||||
<AutoScalingGroupName>my-asg</AutoScalingGroupName>
|
||||
<Details>{"Availability Zone":"us-east-1a"}</Details>
|
||||
<Description>Moving EC2 instance out of Standby: i-5b73d709</Description>
|
||||
</member>
|
||||
</Activities>
|
||||
</ExitStandbyResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>321a11c8-f34c-11e3-a434-7f10009d5849</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ExitStandbyResponse>
|
||||
`
|
||||
var PutLifecycleHookResponse = `
|
||||
<PutLifecycleHookResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<PutLifecycleHookResult/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>1952f458-f645-11e3-bc51-b35178f0274f</RequestId>
|
||||
</ResponseMetadata>
|
||||
</PutLifecycleHookResponse>
|
||||
`
|
||||
var PutNotificationConfigurationResponse = `
|
||||
<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</EnableMetricsCollectionResponse>
|
||||
`
|
||||
var PutScalingPolicyResponse = `
|
||||
<PutScalingPolicyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<PutScalingPolicyResult>
|
||||
<PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:b0dcf5e8-02e6-4e31-9719-0675d0dc31ae:autoScalingGroupName/my-test-asg:policyName/my-scaleout-policy</PolicyARN>
|
||||
</PutScalingPolicyResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>3cfc6fef-c08b-11e2-a697-2922EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</PutScalingPolicyResponse>
|
||||
`
|
||||
var PutScheduledUpdateGroupActionResponse = `
|
||||
<PutScheduledUpdateGroupActionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>3bc8c9bc-6a62-11e2-8a51-4b8a1EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</PutScheduledUpdateGroupActionResponse>
|
||||
`
|
||||
var ResumeProcessesResponse = `
|
||||
<ResumeProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ResumeProcessesResponse>
|
||||
`
|
||||
var SetDesiredCapacityResponse = `
|
||||
<SetDesiredCapacityResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>9fb7e2db-6998-11e2-a985-57c82EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</SetDesiredCapacityResponse>
|
||||
`
|
||||
var SetInstanceHealthResponse = `
|
||||
<SetInstanceHealthResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>9fb7e2db-6998-11e2-a985-57c82EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</SetInstanceHealthResponse>
|
||||
`
|
||||
var SuspendProcessesResponse = `
|
||||
<SuspendProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</SuspendProcessesResponse>
|
||||
`
|
||||
var TerminateInstanceInAutoScalingGroupResponse = `
|
||||
<TerminateInstanceInAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<TerminateInstanceInAutoScalingGroupResult>
|
||||
<Activity>
|
||||
<StatusCode>InProgress</StatusCode>
|
||||
<ActivityId>cczc44a87-7d04-dsa15-31-d27c219864c5</ActivityId>
|
||||
<Progress>0</Progress>
|
||||
<StartTime>2014-01-26T14:08:30.560Z</StartTime>
|
||||
<Cause>At 2014-01-26T14:08:30Z instance i-br234123 was taken out of service in response to a user request.</Cause>
|
||||
<Details>{"Availability Zone":"us-east-1b"}</Details>
|
||||
<Description>Terminating EC2 instance: i-br234123</Description>
|
||||
</Activity>
|
||||
</TerminateInstanceInAutoScalingGroupResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</TerminateInstanceInAutoScalingGroupResponse>
|
||||
`
|
||||
var UpdateAutoScalingGroupResponse = `
|
||||
<UpdateAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</UpdateAutoScalingGroupResponse>
|
||||
`
|
||||
58
vendor/github.com/goamz/goamz/aws/attempt_test.go
generated
vendored
Normal file
58
vendor/github.com/goamz/goamz/aws/attempt_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func (S) TestAttemptTiming(c *C) {
|
||||
testAttempt := aws.AttemptStrategy{
|
||||
Total: 0.25e9,
|
||||
Delay: 0.1e9,
|
||||
}
|
||||
want := []time.Duration{0, 0.1e9, 0.2e9, 0.2e9}
|
||||
got := make([]time.Duration, 0, len(want)) // avoid allocation when testing timing
|
||||
t0 := time.Now()
|
||||
for a := testAttempt.Start(); a.Next(); {
|
||||
got = append(got, time.Now().Sub(t0))
|
||||
}
|
||||
got = append(got, time.Now().Sub(t0))
|
||||
c.Assert(got, HasLen, len(want))
|
||||
const margin = 0.01e9
|
||||
for i, got := range want {
|
||||
lo := want[i] - margin
|
||||
hi := want[i] + margin
|
||||
if got < lo || got > hi {
|
||||
c.Errorf("attempt %d want %g got %g", i, want[i].Seconds(), got.Seconds())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (S) TestAttemptNextHasNext(c *C) {
|
||||
a := aws.AttemptStrategy{}.Start()
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.Next(), Equals, false)
|
||||
|
||||
a = aws.AttemptStrategy{}.Start()
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.HasNext(), Equals, false)
|
||||
c.Assert(a.Next(), Equals, false)
|
||||
|
||||
a = aws.AttemptStrategy{Total: 2e8}.Start()
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.HasNext(), Equals, true)
|
||||
time.Sleep(2e8)
|
||||
c.Assert(a.HasNext(), Equals, true)
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.Next(), Equals, false)
|
||||
|
||||
a = aws.AttemptStrategy{Total: 1e8, Min: 2}.Start()
|
||||
time.Sleep(1e8)
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.HasNext(), Equals, true)
|
||||
c.Assert(a.Next(), Equals, true)
|
||||
c.Assert(a.HasNext(), Equals, false)
|
||||
c.Assert(a.Next(), Equals, false)
|
||||
}
|
||||
211
vendor/github.com/goamz/goamz/aws/aws_test.go
generated
vendored
Normal file
211
vendor/github.com/goamz/goamz/aws/aws_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
type S struct {
|
||||
environ []string
|
||||
}
|
||||
|
||||
func (s *S) SetUpSuite(c *C) {
|
||||
s.environ = os.Environ()
|
||||
}
|
||||
|
||||
func (s *S) TearDownTest(c *C) {
|
||||
os.Clearenv()
|
||||
for _, kv := range s.environ {
|
||||
l := strings.SplitN(kv, "=", 2)
|
||||
os.Setenv(l[0], l[1])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuthNoHome(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "foo")
|
||||
_, err := aws.SharedAuth()
|
||||
c.Assert(err, ErrorMatches, "Could not get HOME")
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuthNoCredentialsFile(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "foo")
|
||||
os.Setenv("HOME", "/tmp")
|
||||
_, err := aws.SharedAuth()
|
||||
c.Assert(err, ErrorMatches, "Couldn't parse AWS credentials file")
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuthNoProfileInFile(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "foo")
|
||||
|
||||
d, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = os.Mkdir(d+"/.aws", 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\n"), 0644)
|
||||
os.Setenv("HOME", d)
|
||||
|
||||
_, err = aws.SharedAuth()
|
||||
c.Assert(err, ErrorMatches, "Couldn't find profile in AWS credentials file")
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuthNoKeysInProfile(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "bar")
|
||||
|
||||
d, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = os.Mkdir(d+"/.aws", 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\nawsaccesskeyid = AK.."), 0644)
|
||||
os.Setenv("HOME", d)
|
||||
|
||||
_, err = aws.SharedAuth()
|
||||
c.Assert(err, ErrorMatches, "AWS_SECRET_ACCESS_KEY not found in credentials file")
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuthDefaultCredentials(c *C) {
|
||||
os.Clearenv()
|
||||
|
||||
d, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = os.Mkdir(d+"/.aws", 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ioutil.WriteFile(d+"/.aws/credentials", []byte("[default]\naws_access_key_id = access\naws_secret_access_key = secret\n"), 0644)
|
||||
os.Setenv("HOME", d)
|
||||
|
||||
auth, err := aws.SharedAuth()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
|
||||
}
|
||||
|
||||
func (s *S) TestSharedAuth(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_PROFILE", "bar")
|
||||
|
||||
d, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = os.Mkdir(d+"/.aws", 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\naws_access_key_id = access\naws_secret_access_key = secret\n"), 0644)
|
||||
os.Setenv("HOME", d)
|
||||
|
||||
auth, err := aws.SharedAuth()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
|
||||
}
|
||||
|
||||
func (s *S) TestEnvAuthNoSecret(c *C) {
|
||||
os.Clearenv()
|
||||
_, err := aws.EnvAuth()
|
||||
c.Assert(err, ErrorMatches, "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment")
|
||||
}
|
||||
|
||||
func (s *S) TestEnvAuthNoAccess(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "foo")
|
||||
_, err := aws.EnvAuth()
|
||||
c.Assert(err, ErrorMatches, "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment")
|
||||
}
|
||||
|
||||
func (s *S) TestEnvAuth(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "access")
|
||||
auth, err := aws.EnvAuth()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
|
||||
}
|
||||
|
||||
func (s *S) TestEnvAuthAlt(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_KEY", "secret")
|
||||
os.Setenv("AWS_ACCESS_KEY", "access")
|
||||
auth, err := aws.EnvAuth()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
|
||||
}
|
||||
|
||||
func (s *S) TestEnvAuthToken(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_KEY", "secret")
|
||||
os.Setenv("AWS_ACCESS_KEY", "access")
|
||||
os.Setenv("AWS_SESSION_TOKEN", "token")
|
||||
auth, err := aws.EnvAuth()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth.SecretKey, Equals, "secret")
|
||||
c.Assert(auth.AccessKey, Equals, "access")
|
||||
c.Assert(auth.Token(), Equals, "token")
|
||||
}
|
||||
|
||||
func (s *S) TestGetAuthStatic(c *C) {
|
||||
exptdate := time.Now().Add(time.Hour)
|
||||
auth, err := aws.GetAuth("access", "secret", "token", exptdate)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth.AccessKey, Equals, "access")
|
||||
c.Assert(auth.SecretKey, Equals, "secret")
|
||||
c.Assert(auth.Token(), Equals, "token")
|
||||
c.Assert(auth.Expiration(), Equals, exptdate)
|
||||
}
|
||||
|
||||
func (s *S) TestGetAuthEnv(c *C) {
|
||||
os.Clearenv()
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "access")
|
||||
auth, err := aws.GetAuth("", "", "", time.Time{})
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
|
||||
}
|
||||
|
||||
func (s *S) TestEncode(c *C) {
|
||||
c.Assert(aws.Encode("foo"), Equals, "foo")
|
||||
c.Assert(aws.Encode("/"), Equals, "%2F")
|
||||
}
|
||||
|
||||
func (s *S) TestRegionsAreNamed(c *C) {
|
||||
for n, r := range aws.Regions {
|
||||
c.Assert(n, Equals, r.Name)
|
||||
}
|
||||
}
|
||||
121
vendor/github.com/goamz/goamz/aws/client_test.go
generated
vendored
Normal file
121
vendor/github.com/goamz/goamz/aws/client_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Retrieve the response from handler using aws.RetryingClient
|
||||
func serveAndGet(handler http.HandlerFunc) (body string, err error) {
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
resp, err := aws.RetryingClient.Get(ts.URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("Bad status code: %d", resp.StatusCode)
|
||||
}
|
||||
greeting, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return strings.TrimSpace(string(greeting)), nil
|
||||
}
|
||||
|
||||
func TestClient_expected(t *testing.T) {
|
||||
body := "foo bar"
|
||||
|
||||
resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, body)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp != body {
|
||||
t.Fatal("Body not as expected.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_delay(t *testing.T) {
|
||||
body := "baz"
|
||||
wait := 4
|
||||
resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
|
||||
if wait < 0 {
|
||||
// If we dipped to zero delay and still failed.
|
||||
t.Fatal("Never succeeded.")
|
||||
}
|
||||
wait -= 1
|
||||
time.Sleep(time.Second * time.Duration(wait))
|
||||
fmt.Fprintln(w, body)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp != body {
|
||||
t.Fatal("Body not as expected.", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_no4xxRetry(t *testing.T) {
|
||||
tries := 0
|
||||
|
||||
// Fail once before succeeding.
|
||||
_, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
|
||||
tries += 1
|
||||
http.Error(w, "error", 404)
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
if tries != 1 {
|
||||
t.Fatalf("should only try once: %d", tries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_retries(t *testing.T) {
|
||||
body := "biz"
|
||||
failed := false
|
||||
// Fail once before succeeding.
|
||||
resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !failed {
|
||||
http.Error(w, "error", 500)
|
||||
failed = true
|
||||
} else {
|
||||
fmt.Fprintln(w, body)
|
||||
}
|
||||
})
|
||||
if failed != true {
|
||||
t.Error("We didn't retry!")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp != body {
|
||||
t.Fatal("Body not as expected.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_fails(t *testing.T) {
|
||||
tries := 0
|
||||
// Fail 3 times and return the last error.
|
||||
_, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
|
||||
tries += 1
|
||||
http.Error(w, "error", 500)
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tries != 3 {
|
||||
t.Fatal("Didn't retry enough")
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/goamz/goamz/aws/export_test.go
generated
vendored
Normal file
29
vendor/github.com/goamz/goamz/aws/export_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// V4Signer:
|
||||
// Exporting methods for testing
|
||||
|
||||
func (s *V4Signer) RequestTime(req *http.Request) time.Time {
|
||||
return s.requestTime(req)
|
||||
}
|
||||
|
||||
func (s *V4Signer) CanonicalRequest(req *http.Request) string {
|
||||
return s.canonicalRequest(req)
|
||||
}
|
||||
|
||||
func (s *V4Signer) StringToSign(t time.Time, creq string) string {
|
||||
return s.stringToSign(t, creq)
|
||||
}
|
||||
|
||||
func (s *V4Signer) Signature(t time.Time, sts string) string {
|
||||
return s.signature(t, sts)
|
||||
}
|
||||
|
||||
func (s *V4Signer) Authorization(header http.Header, t time.Time, signature string) string {
|
||||
return s.authorization(header, t, signature)
|
||||
}
|
||||
540
vendor/github.com/goamz/goamz/aws/sign_test.go
generated
vendored
Normal file
540
vendor/github.com/goamz/goamz/aws/sign_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
var _ = Suite(&V4SignerSuite{})
|
||||
|
||||
type V4SignerSuite struct {
|
||||
auth aws.Auth
|
||||
region aws.Region
|
||||
cases []V4SignerSuiteCase
|
||||
}
|
||||
|
||||
type V4SignerSuiteCase struct {
|
||||
label string
|
||||
request V4SignerSuiteCaseRequest
|
||||
canonicalRequest string
|
||||
stringToSign string
|
||||
signature string
|
||||
authorization string
|
||||
}
|
||||
|
||||
type V4SignerSuiteCaseRequest struct {
|
||||
method string
|
||||
host string
|
||||
url string
|
||||
headers []string
|
||||
body string
|
||||
}
|
||||
|
||||
func (s *V4SignerSuite) SetUpSuite(c *C) {
|
||||
s.auth = aws.Auth{AccessKey: "AKIDEXAMPLE", SecretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"}
|
||||
s.region = aws.USEast
|
||||
|
||||
// Test cases from the Signature Version 4 Test Suite (http://goo.gl/nguvs0)
|
||||
s.cases = append(s.cases,
|
||||
|
||||
// get-header-key-duplicate
|
||||
V4SignerSuiteCase{
|
||||
label: "get-header-key-duplicate",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar", "zoo:foobar", "zoo:zoobar"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:foobar,zoobar,zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3c52f0eaae2b61329c0a332e3fa15842a37bc5812cf4d80eb64784308850e313",
|
||||
signature: "54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed",
|
||||
},
|
||||
|
||||
// get-header-value-order
|
||||
V4SignerSuiteCase{
|
||||
label: "get-header-value-order",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p:z", "p:a", "p:p", "p:a"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:a,a,p,z\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n94c0389fefe0988cbbedc8606f0ca0b485b48da010d09fc844b45b697c8924fe",
|
||||
signature: "d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d",
|
||||
},
|
||||
|
||||
// get-header-value-trim
|
||||
V4SignerSuiteCase{
|
||||
label: "get-header-value-trim",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p: phfft "},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:phfft\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndddd1902add08da1ac94782b05f9278c08dc7468db178a84f8950d93b30b1f35",
|
||||
signature: "debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592",
|
||||
},
|
||||
|
||||
// get-relative-relative
|
||||
V4SignerSuiteCase{
|
||||
label: "get-relative-relative",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/foo/bar/../..",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// get-relative
|
||||
V4SignerSuiteCase{
|
||||
label: "get-relative",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/foo/..",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// get-slash-dot-slash
|
||||
V4SignerSuiteCase{
|
||||
label: "get-slash-dot-slash",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/./",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// get-slash-pointless-dot
|
||||
V4SignerSuiteCase{
|
||||
label: "get-slash-pointless-dot",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/./foo",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n8021a97572ee460f87ca67f4e8c0db763216d84715f5424a843a5312a3321e2d",
|
||||
signature: "910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a",
|
||||
},
|
||||
|
||||
// get-slash
|
||||
V4SignerSuiteCase{
|
||||
label: "get-slash",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "//",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// get-slashes
|
||||
V4SignerSuiteCase{
|
||||
label: "get-slashes",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "//foo//",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/foo/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n6bb4476ee8745730c9cb79f33a0c70baa6d8af29c0077fa12e4e8f1dd17e7098",
|
||||
signature: "b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19",
|
||||
},
|
||||
|
||||
// get-space
|
||||
V4SignerSuiteCase{
|
||||
label: "get-space",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/%20/foo",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/%20/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n69c45fb9fe3fd76442b5086e50b2e9fec8298358da957b293ef26e506fdfb54b",
|
||||
signature: "f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374",
|
||||
},
|
||||
|
||||
// get-unreserved
|
||||
V4SignerSuiteCase{
|
||||
label: "get-unreserved",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndf63ee3247c0356c696a3b21f8d8490b01fa9cd5bc6550ef5ef5f4636b7b8901",
|
||||
signature: "830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e",
|
||||
},
|
||||
|
||||
// get-utf8
|
||||
V4SignerSuiteCase{
|
||||
label: "get-utf8",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/%E1%88%B4",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/%E1%88%B4\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n27ba31df5dbc6e063d8f87d62eb07143f7f271c5330a917840586ac1c85b6f6b",
|
||||
signature: "8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74",
|
||||
},
|
||||
|
||||
// get-vanilla-empty-query-key
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-empty-query-key",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo=bar",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n0846c2945b0832deb7a463c66af5c4f8bd54ec28c438e67a214445b157c9ddf8",
|
||||
signature: "56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f",
|
||||
},
|
||||
|
||||
// get-vanilla-space-query-parameters
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-space-query-parameters",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo foo=bar bar",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\nfoo%20foo=bar%20bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n6a81658ae0a0a4f73aa72ca7d3b01c9cb0c5d4099f7a5ee897f5a571bfe6f7ff",
|
||||
signature: "c8556bc676129d0806ea8fe6ef182dc095666f4c1582c3d9751d47e4306037c9",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=c8556bc676129d0806ea8fe6ef182dc095666f4c1582c3d9751d47e4306037c9",
|
||||
},
|
||||
|
||||
// get-vanilla-query-order-key-case
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-query-order-key-case",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo=Zoo&foo=aha",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\nfoo=Zoo&foo=aha\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ne25f777ba161a0f1baf778a87faf057187cf5987f17953320e3ca399feb5f00d",
|
||||
signature: "be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09",
|
||||
},
|
||||
|
||||
// get-vanilla-query-order-key
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-query-order-key",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?a=foo&b=foo",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\na=foo&b=foo\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n2f23d14fe13caebf6dfda346285c6d9c14f49eaca8f5ec55c627dd7404f7a727",
|
||||
signature: "0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b",
|
||||
},
|
||||
|
||||
// get-vanilla-query-order-value
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-query-order-value",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo=b&foo=a",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\nfoo=a&foo=b\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n33dffc220e89131f8f6157a35c40903daa658608d9129ff9489e5cf5bbd9b11b",
|
||||
signature: "feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc",
|
||||
},
|
||||
|
||||
// get-vanilla-query-unreserved
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-query-unreserved",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nd2578f3156d4c9d180713d1ff20601d8a3eed0dd35447d24603d7d67414bd6b5",
|
||||
signature: "f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb",
|
||||
},
|
||||
|
||||
// get-vanilla-query
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-query",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// get-vanilla-ut8-query
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla-ut8-query",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/?ሴ=bar",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n%E1%88%B4=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nde5065ff39c131e6c2e2bd19cd9345a794bf3b561eab20b8d97b2093fc2a979e",
|
||||
signature: "6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c",
|
||||
},
|
||||
|
||||
// get-vanilla
|
||||
V4SignerSuiteCase{
|
||||
label: "get-vanilla",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "GET",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
|
||||
signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
|
||||
},
|
||||
|
||||
// post-header-key-case
|
||||
V4SignerSuiteCase{
|
||||
label: "post-header-key-case",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4",
|
||||
signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
|
||||
},
|
||||
|
||||
// post-header-key-sort
|
||||
V4SignerSuiteCase{
|
||||
label: "post-header-key-sort",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n34e1bddeb99e76ee01d63b5e28656111e210529efeec6cdfd46a48e4c734545d",
|
||||
signature: "b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a",
|
||||
},
|
||||
|
||||
// post-header-value-case
|
||||
V4SignerSuiteCase{
|
||||
label: "post-header-value-case",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "zoo:ZOOBAR"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:ZOOBAR\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3aae6d8274b8c03e2cc96fc7d6bda4b9bd7a0a184309344470b2c96953e124aa",
|
||||
signature: "273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7",
|
||||
},
|
||||
|
||||
// post-vanilla-empty-query-value
|
||||
V4SignerSuiteCase{
|
||||
label: "post-vanilla-empty-query-value",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo=bar",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e",
|
||||
signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
|
||||
},
|
||||
|
||||
// post-vanilla-query
|
||||
V4SignerSuiteCase{
|
||||
label: "post-vanilla-query",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/?foo=bar",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e",
|
||||
signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
|
||||
},
|
||||
|
||||
// post-vanilla
|
||||
V4SignerSuiteCase{
|
||||
label: "post-vanilla",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4",
|
||||
signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
|
||||
},
|
||||
|
||||
// post-x-www-form-urlencoded-parameters
|
||||
V4SignerSuiteCase{
|
||||
label: "post-x-www-form-urlencoded-parameters",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"Content-Type:application/x-www-form-urlencoded; charset=utf8", "Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
body: "foo=bar",
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded; charset=utf8\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nc4115f9e54b5cecf192b1eaa23b8e88ed8dc5391bd4fde7b3fff3d9c9fe0af1f",
|
||||
signature: "b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71",
|
||||
},
|
||||
|
||||
// post-x-www-form-urlencoded
|
||||
V4SignerSuiteCase{
|
||||
label: "post-x-www-form-urlencoded",
|
||||
request: V4SignerSuiteCaseRequest{
|
||||
method: "POST",
|
||||
host: "host.foo.com",
|
||||
url: "/",
|
||||
headers: []string{"Content-Type:application/x-www-form-urlencoded", "Date:Mon, 09 Sep 2011 23:36:00 GMT"},
|
||||
body: "foo=bar",
|
||||
},
|
||||
canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a",
|
||||
stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n4c5c6e4b52fb5fb947a8733982a8a5a61b14f04345cbfe6e739236c76dd48f74",
|
||||
signature: "5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc",
|
||||
authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (s *V4SignerSuite) TestCases(c *C) {
|
||||
signer := aws.NewV4Signer(s.auth, "host", s.region)
|
||||
|
||||
for _, testCase := range s.cases {
|
||||
|
||||
req, err := http.NewRequest(testCase.request.method, "http://"+testCase.request.host+testCase.request.url, strings.NewReader(testCase.request.body))
|
||||
c.Assert(err, IsNil, Commentf("Testcase: %s", testCase.label))
|
||||
for _, v := range testCase.request.headers {
|
||||
h := strings.SplitN(v, ":", 2)
|
||||
req.Header.Add(h[0], h[1])
|
||||
}
|
||||
req.Header.Set("host", req.Host)
|
||||
|
||||
t := signer.RequestTime(req)
|
||||
|
||||
canonicalRequest := signer.CanonicalRequest(req)
|
||||
c.Check(canonicalRequest, Equals, testCase.canonicalRequest, Commentf("Testcase: %s", testCase.label))
|
||||
|
||||
stringToSign := signer.StringToSign(t, canonicalRequest)
|
||||
c.Check(stringToSign, Equals, testCase.stringToSign, Commentf("Testcase: %s", testCase.label))
|
||||
|
||||
signature := signer.Signature(t, stringToSign)
|
||||
c.Check(signature, Equals, testCase.signature, Commentf("Testcase: %s", testCase.label))
|
||||
|
||||
authorization := signer.Authorization(req.Header, t, signature)
|
||||
c.Check(authorization, Equals, testCase.authorization, Commentf("Testcase: %s", testCase.label))
|
||||
|
||||
signer.Sign(req)
|
||||
c.Check(req.Header.Get("Authorization"), Equals, testCase.authorization, Commentf("Testcase: %s", testCase.label))
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleV4Signer() {
|
||||
// Get auth from env vars
|
||||
auth, err := aws.EnvAuth()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Create a signer with the auth, name of the service, and aws region
|
||||
signer := aws.NewV4Signer(auth, "dynamodb", aws.USEast)
|
||||
|
||||
// Create a request
|
||||
req, err := http.NewRequest("POST", aws.USEast.DynamoDBEndpoint, strings.NewReader("sample_request"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Date or x-amz-date header is required to sign a request
|
||||
req.Header.Add("Date", time.Now().UTC().Format(http.TimeFormat))
|
||||
|
||||
// Sign the request
|
||||
signer.Sign(req)
|
||||
|
||||
// Issue signed request
|
||||
http.DefaultClient.Do(req)
|
||||
}
|
||||
837
vendor/github.com/goamz/goamz/cloudformation/cloudformation.go
generated
vendored
Normal file
837
vendor/github.com/goamz/goamz/cloudformation/cloudformation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,837 @@
|
|||
//
|
||||
// cloudformation: This package provides types and functions to interact with the AWS CloudFormation API
|
||||
//
|
||||
// Depends on https://github.com/goamz/goamz
|
||||
//
|
||||
|
||||
package cloudformation
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
)
|
||||
|
||||
// The CloudFormation type encapsulates operations within a specific EC2 region.
|
||||
type CloudFormation struct {
|
||||
aws.Auth
|
||||
aws.Region
|
||||
}
|
||||
|
||||
// New creates a new CloudFormation Client.
|
||||
func New(auth aws.Auth, region aws.Region) *CloudFormation {
|
||||
|
||||
return &CloudFormation{auth, region}
|
||||
|
||||
}
|
||||
|
||||
const debug = false
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Request dispatching logic.
|
||||
|
||||
// Error encapsulates an error returned by the AWS CloudFormation API.
|
||||
//
|
||||
// See http://goo.gl/zDZbuQ for more details.
|
||||
type Error struct {
|
||||
// HTTP status code (200, 403, ...)
|
||||
StatusCode int
|
||||
// Error type
|
||||
Type string `xml:"Type"`
|
||||
// CloudFormation error code
|
||||
Code string `xml:"Code"`
|
||||
// The human-oriented error message
|
||||
Message string `xml:"Message"`
|
||||
RequestId string `xml:"RequestID"`
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
if err.Code == "" {
|
||||
return err.Message
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (%s)", err.Message, err.Code)
|
||||
}
|
||||
|
||||
type xmlErrors struct {
|
||||
RequestId string `xml:"RequestId"`
|
||||
Errors []Error `xml:"Error"`
|
||||
}
|
||||
|
||||
func (c *CloudFormation) query(params map[string]string, resp interface{}) error {
|
||||
params["Version"] = "2010-05-15"
|
||||
|
||||
data := strings.NewReader(multimap(params).Encode())
|
||||
|
||||
hreq, err := http.NewRequest("POST", c.Region.CloudFormationEndpoint+"/", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
||||
|
||||
token := c.Auth.Token()
|
||||
if token != "" {
|
||||
hreq.Header.Set("X-Amz-Security-Token", token)
|
||||
}
|
||||
|
||||
signer := aws.NewV4Signer(c.Auth, "cloudformation", c.Region)
|
||||
signer.Sign(hreq)
|
||||
|
||||
if debug {
|
||||
log.Printf("%v -> {\n", hreq)
|
||||
}
|
||||
r, err := http.DefaultClient.Do(hreq)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error calling Amazon")
|
||||
return err
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
if debug {
|
||||
dump, _ := httputil.DumpResponse(r, true)
|
||||
log.Printf("response:\n")
|
||||
log.Printf("%v\n}\n", string(dump))
|
||||
}
|
||||
if r.StatusCode != 200 {
|
||||
return buildError(r)
|
||||
}
|
||||
err = xml.NewDecoder(r.Body).Decode(resp)
|
||||
return err
|
||||
}
|
||||
|
||||
func buildError(r *http.Response) error {
|
||||
var (
|
||||
err Error
|
||||
errors xmlErrors
|
||||
)
|
||||
xml.NewDecoder(r.Body).Decode(&errors)
|
||||
if len(errors.Errors) > 0 {
|
||||
err = errors.Errors[0]
|
||||
}
|
||||
|
||||
err.RequestId = errors.RequestId
|
||||
err.StatusCode = r.StatusCode
|
||||
if err.Message == "" {
|
||||
err.Message = r.Status
|
||||
}
|
||||
return &err
|
||||
}
|
||||
|
||||
func makeParams(action string) map[string]string {
|
||||
params := make(map[string]string)
|
||||
params["Action"] = action
|
||||
return params
|
||||
}
|
||||
|
||||
func multimap(p map[string]string) url.Values {
|
||||
q := make(url.Values, len(p))
|
||||
for k, v := range p {
|
||||
q[k] = []string{v}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// addParamsList adds params in the form of param.member.N to the params map
|
||||
func addParamsList(params map[string]string, label string, ids []string) {
|
||||
for i, id := range ids {
|
||||
params[label+"."+strconv.Itoa(i+1)] = id
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// API Supported Types and Methods
|
||||
|
||||
// SimpleResp is the basic response from most actions.
|
||||
type SimpleResp struct {
|
||||
XMLName xml.Name
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// CancelUpdateStack cancels an update on the specified stack.
|
||||
// If the call completes successfully, the stack will roll back the update and revert
|
||||
// to the previous stack configuration.
|
||||
//
|
||||
// See http://goo.gl/ZE6fOa for more details
|
||||
func (c *CloudFormation) CancelUpdateStack(stackName string) (resp *SimpleResp, err error) {
|
||||
params := makeParams("CancelUpdateStack")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
resp = new(SimpleResp)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Parameter encapsulates the cloudstack paramter data type
|
||||
//
|
||||
// See http://goo.gl/2rg9eG for more details
|
||||
type Parameter struct {
|
||||
ParameterKey string `xml:"ParameterKey"`
|
||||
ParameterValue string `xml:"ParameterValue"`
|
||||
UsePreviousValue bool `xml:"UsePreviousValue"`
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Key string `xml:"Key"`
|
||||
Value string `xml:"Value"`
|
||||
}
|
||||
|
||||
// CreateStackParams wraps CreateStack request options
|
||||
//
|
||||
// See http://goo.gl/yDZYuV for more information
|
||||
type CreateStackParams struct {
|
||||
Capabilities []string
|
||||
DisableRollback bool
|
||||
NotificationARNs []string
|
||||
OnFailure string
|
||||
Parameters []Parameter
|
||||
StackName string
|
||||
StackPolicyBody string
|
||||
StackPolicyURL string
|
||||
Tags []Tag
|
||||
TemplateBody string
|
||||
TemplateURL string
|
||||
TimeoutInMinutes int
|
||||
}
|
||||
|
||||
// CreateStackResponse wraps a CreateStack call response
|
||||
//
|
||||
// See http://goo.gl/yDZYuV for more details
|
||||
type CreateStackResponse struct {
|
||||
StackId string `xml:"CreateStackResult>StackId"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// CreateStack creates a stack as specified in the template. After the call completes successfully,
|
||||
// the stack creation starts.
|
||||
//
|
||||
// Required params: StackName
|
||||
//
|
||||
// See http://goo.gl/yDZYuV for more details
|
||||
func (c *CloudFormation) CreateStack(options *CreateStackParams) (
|
||||
resp *CreateStackResponse, err error) {
|
||||
params := makeParams("CreateStack")
|
||||
|
||||
params["StackName"] = options.StackName
|
||||
|
||||
if options.DisableRollback {
|
||||
params["DisableRollback"] = strconv.FormatBool(options.DisableRollback)
|
||||
}
|
||||
if options.OnFailure != "" {
|
||||
params["OnFailure"] = options.OnFailure
|
||||
}
|
||||
if options.StackPolicyBody != "" {
|
||||
params["StackPolicyBody"] = options.StackPolicyBody
|
||||
}
|
||||
if options.StackPolicyURL != "" {
|
||||
params["StackPolicyURL"] = options.StackPolicyURL
|
||||
}
|
||||
if options.TemplateBody != "" {
|
||||
params["TemplateBody"] = options.TemplateBody
|
||||
}
|
||||
if options.TemplateURL != "" {
|
||||
params["TemplateURL"] = options.TemplateURL
|
||||
}
|
||||
if options.TimeoutInMinutes != 0 {
|
||||
params["TimeoutInMinutes"] = strconv.Itoa(options.TimeoutInMinutes)
|
||||
}
|
||||
if len(options.Capabilities) > 0 {
|
||||
addParamsList(params, "Capabilities.member", options.Capabilities)
|
||||
}
|
||||
if len(options.NotificationARNs) > 0 {
|
||||
addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
|
||||
}
|
||||
// Add any parameters
|
||||
for i, t := range options.Parameters {
|
||||
key := "Parameters.member.%d.%s"
|
||||
index := i + 1
|
||||
params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
|
||||
params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
|
||||
params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
|
||||
}
|
||||
// Add any tags
|
||||
for i, t := range options.Tags {
|
||||
key := "Tags.member.%d.%s"
|
||||
index := i + 1
|
||||
params[fmt.Sprintf(key, index, "Key")] = t.Key
|
||||
params[fmt.Sprintf(key, index, "Value")] = t.Value
|
||||
}
|
||||
|
||||
resp = new(CreateStackResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DeleteStack deletes a specified stack.
|
||||
// Once the call completes successfully, stack deletion starts.
|
||||
//
|
||||
// See http://goo.gl/CVMpxC for more details
|
||||
func (c *CloudFormation) DeleteStack(stackName string) (resp *SimpleResp, err error) {
|
||||
params := makeParams("DeleteStack")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
resp = new(SimpleResp)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StackEvent encapsulates the StackEvent data type
|
||||
//
|
||||
// See http://goo.gl/EHwiMf for more details
|
||||
type StackEvent struct {
|
||||
EventId string `xml:"EventId"`
|
||||
LogicalResourceId string `xml:"LogicalResourceId"`
|
||||
PhysicalResourceId string `xml:"PhysicalResourceId"`
|
||||
ResourceProperties string `xml:"ResourceProperties"`
|
||||
ResourceStatus string `xml:"ResourceStatus"`
|
||||
ResourceStatusReason string `xml:"ResourceStatusReason"`
|
||||
ResourceType string `xml:"ResourceType"`
|
||||
StackId string `xml:"StackId"`
|
||||
StackName string `xml:"StackName"`
|
||||
Timestamp time.Time `xml:"Timestamp"`
|
||||
}
|
||||
|
||||
// DescribeStackEventsResponse wraps a response returned by DescribeStackEvents request
|
||||
//
|
||||
// See http://goo.gl/zqj4Bz for more details
|
||||
type DescribeStackEventsResponse struct {
|
||||
NextToken string `xml:"DescribeStackEventsResult>NextToken"`
|
||||
StackEvents []StackEvent `xml:"DescribeStackEventsResult>StackEvents>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// DescribeStackEvents returns all stack related events for a specified stack.
|
||||
//
|
||||
// See http://goo.gl/zqj4Bz for more details
|
||||
func (c *CloudFormation) DescribeStackEvents(stackName string, nextToken string) (
|
||||
resp *DescribeStackEventsResponse, err error) {
|
||||
params := makeParams("DescribeStackEvents")
|
||||
|
||||
if stackName != "" {
|
||||
params["StackName"] = stackName
|
||||
}
|
||||
if nextToken != "" {
|
||||
params["NextToken"] = nextToken
|
||||
}
|
||||
|
||||
resp = new(DescribeStackEventsResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StackResourceDetail encapsulates the StackResourceDetail data type
|
||||
//
|
||||
// See http://goo.gl/flce6I for more details
|
||||
type StackResourceDetail struct {
|
||||
Description string `xml:"Description"`
|
||||
LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
|
||||
LogicalResourceId string `xml:"LogicalResourceId"`
|
||||
Metadata string `xml:"Metadata"`
|
||||
PhysicalResourceId string `xml:"PhysicalResourceId"`
|
||||
ResourceStatus string `xml:"ResourceStatus"`
|
||||
ResourceStatusReason string `xml:"ResourceStatusReason"`
|
||||
ResourceType string `xml:"ResourceType"`
|
||||
StackId string `xml:"StackId"`
|
||||
StackName string `xml:"StackName"`
|
||||
}
|
||||
|
||||
// DescribeStackResourceResponse wraps a response returned by DescribeStackResource request
|
||||
//
|
||||
// See http://goo.gl/6pfPFs for more details
|
||||
type DescribeStackResourceResponse struct {
|
||||
StackResourceDetail StackResourceDetail `xml:"DescribeStackResourceResult>StackResourceDetail"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// DescribeStackResource returns a description of the specified resource in the specified stack.
|
||||
// For deleted stacks, DescribeStackResource returns resource information
|
||||
// for up to 90 days after the stack has been deleted.
|
||||
//
|
||||
// Required params: stackName, logicalResourceId
|
||||
//
|
||||
// See http://goo.gl/6pfPFs for more details
|
||||
func (c *CloudFormation) DescribeStackResource(stackName string, logicalResourceId string) (
|
||||
resp *DescribeStackResourceResponse, err error) {
|
||||
params := makeParams("DescribeStackResource")
|
||||
|
||||
params["StackName"] = stackName
|
||||
params["LogicalResourceId"] = logicalResourceId
|
||||
|
||||
resp = new(DescribeStackResourceResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StackResource encapsulates the StackResource data type
|
||||
//
|
||||
// See http://goo.gl/j4eli5 for more details
|
||||
type StackResource struct {
|
||||
Description string `xml:"Description"`
|
||||
LogicalResourceId string `xml:"LogicalResourceId"`
|
||||
PhysicalResourceId string `xml:"PhysicalResourceId"`
|
||||
ResourceStatus string `xml:"ResourceStatus"`
|
||||
ResourceStatusReason string `xml:"ResourceStatusReason"`
|
||||
ResourceType string `xml:"ResourceType"`
|
||||
StackId string `xml:"StackId"`
|
||||
StackName string `xml:"StackName"`
|
||||
Timestamp time.Time `xml:"Timestamp"`
|
||||
}
|
||||
|
||||
// DescribeStackResourcesResponse wraps a response returned by DescribeStackResources request
|
||||
//
|
||||
// See http://goo.gl/YnY5rs for more details
|
||||
type DescribeStackResourcesResponse struct {
|
||||
StackResources []StackResource `xml:"DescribeStackResourcesResult>StackResources>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// DescribeStackResources returns AWS resource descriptions for running and deleted stacks.
|
||||
// If stackName is specified, all the associated resources that are part of the stack are returned.
|
||||
// If physicalResourceId is specified, the associated resources of the stack that the resource
|
||||
// belongs to are returned.
|
||||
//
|
||||
// Only the first 100 resources will be returned. If your stack has more resources than this,
|
||||
// you should use ListStackResources instead.
|
||||
//
|
||||
// See http://goo.gl/YnY5rs for more details
|
||||
func (c *CloudFormation) DescribeStackResources(stackName, physicalResourceId, logicalResourceId string) (
|
||||
resp *DescribeStackResourcesResponse, err error) {
|
||||
params := makeParams("DescribeStackResources")
|
||||
|
||||
if stackName != "" {
|
||||
params["StackName"] = stackName
|
||||
}
|
||||
if physicalResourceId != "" {
|
||||
params["PhysicalResourceId"] = physicalResourceId
|
||||
}
|
||||
if logicalResourceId != "" {
|
||||
params["LogicalResourceId"] = logicalResourceId
|
||||
}
|
||||
|
||||
resp = new(DescribeStackResourcesResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Output encapsulates the Output AWS data type
|
||||
//
|
||||
// See http://goo.gl/UOn7q6 for more information
|
||||
type Output struct {
|
||||
Description string `xml:"Description"`
|
||||
OutputKey string `xml:"OutputKey"`
|
||||
OutputValue string `xml:"OutputValue"`
|
||||
}
|
||||
|
||||
// Stack encapsulates the Stack AWS data type
|
||||
//
|
||||
// See http://goo.gl/yDZYuV for more information
|
||||
type Stack struct {
|
||||
Capabilities []string `xml:"Capabilities>member"`
|
||||
CreationTime time.Time `xml:"CreationTime"`
|
||||
Description string `xml:"Description"`
|
||||
DisableRollback bool `xml:"DisableRollback"`
|
||||
LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
|
||||
NotificationARNs []string `xml:"NotificationARNs>member"`
|
||||
Outputs []Output `xml:"Outputs>member"`
|
||||
Parameters []Parameter `xml:"Parameters>member"`
|
||||
StackId string `xml:"StackId"`
|
||||
StackName string `xml:"StackName"`
|
||||
StackStatus string `xml:"StackStatus"`
|
||||
StackStatusReason string `xml:"StackStatusReason"`
|
||||
Tags []Tag `xml:"Tags>member"`
|
||||
TimeoutInMinutes int `xml:"TimeoutInMinutes"`
|
||||
}
|
||||
|
||||
// DescribeStacksResponse wraps a response returned by DescribeStacks request
|
||||
//
|
||||
// See http://goo.gl/UOLsXD for more information
|
||||
type DescribeStacksResponse struct {
|
||||
NextToken string `xml:"DescribeStacksResult>NextToken"`
|
||||
Stacks []Stack `xml:"DescribeStacksResult>Stacks>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// DescribeStacks returns the description for the specified stack;
|
||||
// If no stack name was specified, then it returns the description for all the stacks created.
|
||||
//
|
||||
// See http://goo.gl/UOLsXD for more information
|
||||
func (c *CloudFormation) DescribeStacks(stackName string, nextToken string) (
|
||||
resp *DescribeStacksResponse, err error) {
|
||||
params := makeParams("DescribeStacks")
|
||||
|
||||
if stackName != "" {
|
||||
params["StackName"] = stackName
|
||||
}
|
||||
if nextToken != "" {
|
||||
params["NextToken"] = nextToken
|
||||
}
|
||||
|
||||
resp = new(DescribeStacksResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// EstimateTemplateCostResponse wraps a response returned by EstimateTemplateCost request
|
||||
//
|
||||
// See http://goo.gl/PD9hle for more information
|
||||
type EstimateTemplateCostResponse struct {
|
||||
Url string `xml:"EstimateTemplateCostResult>Url"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// EstimateTemplateCost returns the estimated monthly cost of a template.
|
||||
// The return value is an AWS Simple Monthly Calculator URL with a query string that describes
|
||||
// the resources required to run the template.
|
||||
//
|
||||
// See http://goo.gl/PD9hle for more information
|
||||
func (c *CloudFormation) EstimateTemplateCost(parameters []Parameter, templateBody, templateUrl string) (
|
||||
resp *EstimateTemplateCostResponse, err error) {
|
||||
params := makeParams("EstimateTemplateCost")
|
||||
|
||||
if templateBody != "" {
|
||||
params["TemplateBody"] = templateBody
|
||||
}
|
||||
if templateUrl != "" {
|
||||
params["TemplateURL"] = templateUrl
|
||||
}
|
||||
// Add any parameters
|
||||
for i, t := range parameters {
|
||||
key := "Parameters.member.%d.%s"
|
||||
index := i + 1
|
||||
params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
|
||||
params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
|
||||
params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
|
||||
}
|
||||
|
||||
resp = new(EstimateTemplateCostResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetStackPolicyResponse wraps a response returned by GetStackPolicy request
|
||||
//
|
||||
// See http://goo.gl/iZFSgy for more information
|
||||
type GetStackPolicyResponse struct {
|
||||
StackPolicyBody string `xml:"GetStackPolicyResult>StackPolicyBody"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// GetStackPolicy returns the stack policy for a specified stack. If a stack doesn't have a policy,
|
||||
// a null value is returned.
|
||||
//
|
||||
// See http://goo.gl/iZFSgy for more information
|
||||
func (c *CloudFormation) GetStackPolicy(stackName string) (
|
||||
resp *GetStackPolicyResponse, err error) {
|
||||
params := makeParams("GetStackPolicy")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
resp = new(GetStackPolicyResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetTemplateResponse wraps a response returned by GetTemplate request
|
||||
//
|
||||
// See http://goo.gl/GU59CB for more information
|
||||
type GetTemplateResponse struct {
|
||||
TemplateBody string `xml:"GetTemplateResult>TemplateBody"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// GetTemplate returns the template body for a specified stack.
|
||||
// You can get the template for running or deleted stacks
|
||||
//
|
||||
// Required Params: StackName - The name or the unique identifier associated with the stack,
|
||||
// which are not always interchangeable:
|
||||
// Running stacks: You can specify either the stack's name or its unique stack ID.
|
||||
// Deleted stacks: You must specify the unique stack ID.
|
||||
//
|
||||
// See http://goo.gl/GU59CB for more information
|
||||
func (c *CloudFormation) GetTemplate(stackName string) (
|
||||
resp *GetTemplateResponse, err error) {
|
||||
params := makeParams("GetTemplate")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
resp = new(GetTemplateResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StackResourceSummary encapsulates the StackResourceSummary data type
|
||||
//
|
||||
// See http://goo.gl/Af0vcm for more details
|
||||
type StackResourceSummary struct {
|
||||
LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
|
||||
LogicalResourceId string `xml:"LogicalResourceId"`
|
||||
PhysicalResourceId string `xml:"PhysicalResourceId"`
|
||||
ResourceStatus string `xml:"ResourceStatus"`
|
||||
ResourceStatusReason string `xml:"ResourceStatusReason"`
|
||||
ResourceType string `xml:"ResourceType"`
|
||||
}
|
||||
|
||||
// ListStackResourcesResponse wraps a response returned by ListStackResources request
|
||||
//
|
||||
// See http://goo.gl/JUCgLf for more details
|
||||
type ListStackResourcesResponse struct {
|
||||
NextToken string `xml:"ListStackResourcesResult>NextToken"`
|
||||
StackResourceSummaries []StackResourceSummary `xml:"ListStackResourcesResult>StackResourceSummaries>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// ListStackResources returns descriptions of all resources of the specified stack.
|
||||
// For deleted stacks, ListStackResources returns resource information for up to 90 days
|
||||
// after the stack has been deleted.
|
||||
//
|
||||
// Required Params: stackName - the name or the unique identifier associated with the stack,
|
||||
// which are not always interchangeable:
|
||||
// Running stacks: You can specify either the stack's name or its unique stack ID.
|
||||
// Deleted stacks: You must specify the unique stack ID.
|
||||
//
|
||||
// See http://goo.gl/JUCgLf for more details
|
||||
func (c *CloudFormation) ListStackResources(stackName, nextToken string) (
|
||||
resp *ListStackResourcesResponse, err error) {
|
||||
params := makeParams("ListStackResources")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
if nextToken != "" {
|
||||
params["NextToken"] = nextToken
|
||||
}
|
||||
|
||||
resp = new(ListStackResourcesResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StackSummary encapsulates the StackSummary data type
|
||||
//
|
||||
// See http://goo.gl/35j3wf for more details
|
||||
type StackSummary struct {
|
||||
CreationTime time.Time `xml:"CreationTime"`
|
||||
DeletionTime time.Time `xml:"DeletionTime"`
|
||||
LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
|
||||
StackId string `xml:"StackId"`
|
||||
StackName string `xml:"StackName"`
|
||||
StackStatus string `xml:"StackStatus"`
|
||||
StackStatusReason string `xml:"StackStatusReason"`
|
||||
TemplateDescription string `xml:"TemplateDescription"`
|
||||
}
|
||||
|
||||
// ListStacksResponse wraps a response returned by ListStacks request
|
||||
//
|
||||
// See http://goo.gl/UWi6nm for more details
|
||||
type ListStacksResponse struct {
|
||||
NextToken string `xml:"ListStacksResult>NextToken"`
|
||||
StackSummaries []StackSummary `xml:"ListStacksResult>StackSummaries>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// ListStacks Returns the summary information for stacks whose status matches the specified StackStatusFilter.
|
||||
// Summary information for stacks that have been deleted is kept for 90 days after the stack is deleted.
|
||||
// If no StackStatusFilter is specified, summary information for all stacks is returned
|
||||
// (including existing stacks and stacks that have been deleted).
|
||||
//
|
||||
// See http://goo.gl/UWi6nm for more details
|
||||
func (c *CloudFormation) ListStacks(stackStatusFilters []string, nextToken string) (
|
||||
resp *ListStacksResponse, err error) {
|
||||
params := makeParams("ListStacks")
|
||||
|
||||
if nextToken != "" {
|
||||
params["NextToken"] = nextToken
|
||||
}
|
||||
|
||||
if len(stackStatusFilters) > 0 {
|
||||
addParamsList(params, "StackStatusFilter.member", stackStatusFilters)
|
||||
}
|
||||
|
||||
resp = new(ListStacksResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SetStackPolicy sets a stack policy for a specified stack.
|
||||
//
|
||||
// Required Params: stackName
|
||||
//
|
||||
// See http://goo.gl/iY9ohu for more information
|
||||
func (c *CloudFormation) SetStackPolicy(stackName, stackPolicyBody, stackPolicyUrl string) (
|
||||
resp *SimpleResp, err error) {
|
||||
params := makeParams("SetStackPolicy")
|
||||
|
||||
params["StackName"] = stackName
|
||||
|
||||
if stackPolicyBody != "" {
|
||||
params["StackPolicyBody"] = stackPolicyBody
|
||||
}
|
||||
if stackPolicyUrl != "" {
|
||||
params["StackPolicyURL"] = stackPolicyUrl
|
||||
}
|
||||
|
||||
resp = new(SimpleResp)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UpdateStackParams wraps UpdateStack request options
|
||||
//
|
||||
// See http://goo.gl/LvkhZq for more information
|
||||
type UpdateStackParams struct {
|
||||
Capabilities []string
|
||||
NotificationARNs []string
|
||||
Parameters []Parameter
|
||||
StackName string
|
||||
StackPolicyBody string
|
||||
StackPolicyDuringUpdateBody string
|
||||
StackPolicyDuringUpdateURL string
|
||||
StackPolicyURL string
|
||||
TemplateBody string
|
||||
TemplateURL string
|
||||
UsePreviousTemplate bool
|
||||
}
|
||||
|
||||
// UpdateStackResponse wraps the UpdateStack call response
|
||||
//
|
||||
// See http://goo.gl/LvkhZq for more information
|
||||
type UpdateStackResponse struct {
|
||||
StackId string `xml:"UpdateStackResult>StackId"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// UpdateStack updates a stack as specified in the template.
|
||||
// After the call completes successfully, the stack update starts.
|
||||
// You can check the status of the stack via the DescribeStacks action.
|
||||
//
|
||||
// Required Params: options.StackName
|
||||
//
|
||||
// See http://goo.gl/LvkhZq for more information
|
||||
func (c *CloudFormation) UpdateStack(options *UpdateStackParams) (
|
||||
resp *UpdateStackResponse, err error) {
|
||||
params := makeParams("UpdateStack")
|
||||
|
||||
params["StackName"] = options.StackName
|
||||
|
||||
if options.StackPolicyBody != "" {
|
||||
params["StackPolicyBody"] = options.StackPolicyBody
|
||||
}
|
||||
if options.StackPolicyDuringUpdateBody != "" {
|
||||
params["StackPolicyDuringUpdateBody"] = options.StackPolicyDuringUpdateBody
|
||||
}
|
||||
if options.StackPolicyDuringUpdateURL != "" {
|
||||
params["StackPolicyDuringUpdateURL"] = options.StackPolicyDuringUpdateURL
|
||||
}
|
||||
if options.StackPolicyURL != "" {
|
||||
params["StackPolicyURL"] = options.StackPolicyURL
|
||||
}
|
||||
if options.TemplateBody != "" {
|
||||
params["TemplateBody"] = options.TemplateBody
|
||||
}
|
||||
if options.TemplateURL != "" {
|
||||
params["TemplateURL"] = options.TemplateURL
|
||||
}
|
||||
if options.UsePreviousTemplate {
|
||||
params["UsePreviousTemplate"] = strconv.FormatBool(options.UsePreviousTemplate)
|
||||
}
|
||||
|
||||
if len(options.Capabilities) > 0 {
|
||||
addParamsList(params, "Capabilities.member", options.Capabilities)
|
||||
}
|
||||
if len(options.NotificationARNs) > 0 {
|
||||
addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
|
||||
}
|
||||
// Add any parameters
|
||||
for i, t := range options.Parameters {
|
||||
key := "Parameters.member.%d.%s"
|
||||
index := i + 1
|
||||
params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
|
||||
params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
|
||||
params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
|
||||
}
|
||||
|
||||
resp = new(UpdateStackResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// TemplateParameter encapsulates the AWS TemplateParameter data type
|
||||
//
|
||||
// See http://goo.gl/OBhNzk for more information
|
||||
type TemplateParameter struct {
|
||||
DefaultValue string `xml:"DefaultValue"`
|
||||
Description string `xml:Description"`
|
||||
NoEcho bool `xml:NoEcho"`
|
||||
ParameterKey string `xml:ParameterKey"`
|
||||
}
|
||||
|
||||
// ValidateTemplateResponse wraps the ValidateTemplate call response
|
||||
//
|
||||
// See http://goo.gl/OBhNzk for more information
|
||||
type ValidateTemplateResponse struct {
|
||||
Capabilities []string `xml:"ValidateTemplateResult>Capabilities>member"`
|
||||
CapabilitiesReason string `xml:"ValidateTemplateResult>CapabilitiesReason"`
|
||||
Description string `xml:"ValidateTemplateResult>Description"`
|
||||
Parameters []TemplateParameter `xml:"ValidateTemplateResult>Parameters>member"`
|
||||
RequestId string `xml:"ResponseMetadata>RequestId"`
|
||||
}
|
||||
|
||||
// ValidateTemplate validates a specified template.
|
||||
//
|
||||
// See http://goo.gl/OBhNzk for more information
|
||||
func (c *CloudFormation) ValidateTemplate(templateBody, templateUrl string) (
|
||||
resp *ValidateTemplateResponse, err error) {
|
||||
params := makeParams("ValidateTemplate")
|
||||
|
||||
if templateBody != "" {
|
||||
params["TemplateBody"] = templateBody
|
||||
}
|
||||
if templateUrl != "" {
|
||||
params["TemplateURL"] = templateUrl
|
||||
}
|
||||
|
||||
resp = new(ValidateTemplateResponse)
|
||||
if err := c.query(params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
653
vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go
generated
vendored
Normal file
653
vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
package cloudformation_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
cf "github.com/goamz/goamz/cloudformation"
|
||||
"github.com/goamz/goamz/testutil"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
type S struct {
|
||||
cf *cf.CloudFormation
|
||||
}
|
||||
|
||||
var testServer = testutil.NewHTTPServer()
|
||||
|
||||
var mockTest bool
|
||||
|
||||
func (s *S) SetUpSuite(c *C) {
|
||||
testServer.Start()
|
||||
auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
|
||||
s.cf = cf.New(auth, aws.Region{CloudFormationEndpoint: testServer.URL})
|
||||
}
|
||||
|
||||
func (s *S) TearDownTest(c *C) {
|
||||
testServer.Flush()
|
||||
}
|
||||
|
||||
func (s *S) TestCancelUpdateStack(c *C) {
|
||||
testServer.Response(200, nil, CancelUpdateStackResponse)
|
||||
|
||||
resp, err := s.cf.CancelUpdateStack("foo")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "CancelUpdateStack")
|
||||
c.Assert(values.Get("StackName"), Equals, "foo")
|
||||
// Response test
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestCreateStack(c *C) {
|
||||
testServer.Response(200, nil, CreateStackResponse)
|
||||
|
||||
stackParams := &cf.CreateStackParams{
|
||||
NotificationARNs: []string{"arn:aws:sns:us-east-1:1234567890:my-topic"},
|
||||
Parameters: []cf.Parameter{
|
||||
{
|
||||
ParameterKey: "AvailabilityZone",
|
||||
ParameterValue: "us-east-1a",
|
||||
},
|
||||
},
|
||||
StackName: "MyStack",
|
||||
TemplateBody: "[Template Document]",
|
||||
}
|
||||
resp, err := s.cf.CreateStack(stackParams)
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "CreateStack")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
|
||||
c.Assert(values.Get("TemplateBody"), Equals, "[Template Document]")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
|
||||
// Response test
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
c.Assert(resp.StackId, Equals, "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83")
|
||||
}
|
||||
|
||||
func (s *S) TestCreateStackWithInvalidParams(c *C) {
|
||||
testServer.Response(400, nil, CreateStackWithInvalidParamsResponse)
|
||||
//testServer.Response(200, nil, DeleteAutoScalingGroupResponse)
|
||||
|
||||
cfTemplate := `
|
||||
{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
"Description" : "Sample template",
|
||||
"Parameters" : {
|
||||
"KeyName" : {
|
||||
"Description" : "key pair",
|
||||
"Type" : "String"
|
||||
}
|
||||
},
|
||||
"Resources" : {
|
||||
"Ec2Instance" : {
|
||||
"Type" : "AWS::EC2::Instance",
|
||||
"Properties" : {
|
||||
"KeyName" : { "Ref" : "KeyName" },
|
||||
"ImageId" : "ami-7f418316",
|
||||
"UserData" : { "Fn::Base64" : "80" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"Outputs" : {
|
||||
"InstanceId" : {
|
||||
"Description" : "InstanceId of the newly created EC2 instance",
|
||||
"Value" : { "Ref" : "Ec2Instance" }
|
||||
}
|
||||
}`
|
||||
|
||||
stackParams := &cf.CreateStackParams{
|
||||
Capabilities: []string{"CAPABILITY_IAM"},
|
||||
DisableRollback: true,
|
||||
NotificationARNs: []string{
|
||||
"arn:aws:sns:us-east-1:1234567890:my-topic",
|
||||
"arn:aws:sns:us-east-1:1234567890:my-topic2",
|
||||
},
|
||||
OnFailure: "ROLLBACK",
|
||||
Parameters: []cf.Parameter{
|
||||
{
|
||||
ParameterKey: "AvailabilityZone",
|
||||
ParameterValue: "us-east-1a",
|
||||
},
|
||||
},
|
||||
StackName: "MyStack",
|
||||
StackPolicyBody: "{PolicyBody}",
|
||||
StackPolicyURL: "http://stack-policy-url",
|
||||
Tags: []cf.Tag{
|
||||
{
|
||||
Key: "TagKey",
|
||||
Value: "TagValue",
|
||||
},
|
||||
},
|
||||
TemplateBody: cfTemplate,
|
||||
TemplateURL: "http://url",
|
||||
TimeoutInMinutes: 20,
|
||||
}
|
||||
resp, err := s.cf.CreateStack(stackParams)
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(resp, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "CreateStack")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
|
||||
c.Assert(values.Get("NotificationARNs.member.2"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic2")
|
||||
c.Assert(values.Get("Capabilities.member.1"), Equals, "CAPABILITY_IAM")
|
||||
c.Assert(values.Get("TemplateBody"), Equals, cfTemplate)
|
||||
c.Assert(values.Get("TemplateURL"), Equals, "http://url")
|
||||
c.Assert(values.Get("StackPolicyBody"), Equals, "{PolicyBody}")
|
||||
c.Assert(values.Get("StackPolicyURL"), Equals, "http://stack-policy-url")
|
||||
c.Assert(values.Get("OnFailure"), Equals, "ROLLBACK")
|
||||
c.Assert(values.Get("DisableRollback"), Equals, "true")
|
||||
c.Assert(values.Get("Tags.member.1.Key"), Equals, "TagKey")
|
||||
c.Assert(values.Get("Tags.member.1.Value"), Equals, "TagValue")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
|
||||
c.Assert(values.Get("TimeoutInMinutes"), Equals, "20")
|
||||
|
||||
// Response test
|
||||
c.Assert(err.(*cf.Error).RequestId, Equals, "70a76d42-9665-11e2-9fdf-211deEXAMPLE")
|
||||
c.Assert(err.(*cf.Error).Message, Equals, "Either Template URL or Template Body must be specified.")
|
||||
c.Assert(err.(*cf.Error).Type, Equals, "Sender")
|
||||
c.Assert(err.(*cf.Error).Code, Equals, "ValidationError")
|
||||
c.Assert(err.(*cf.Error).StatusCode, Equals, 400)
|
||||
|
||||
}
|
||||
|
||||
func (s *S) TestDeleteStack(c *C) {
|
||||
testServer.Response(200, nil, DeleteStackResponse)
|
||||
|
||||
resp, err := s.cf.DeleteStack("foo")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "DeleteStack")
|
||||
c.Assert(values.Get("StackName"), Equals, "foo")
|
||||
// Response test
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestDescribeStackEvents(c *C) {
|
||||
testServer.Response(200, nil, DescribeStackEventsResponse)
|
||||
|
||||
resp, err := s.cf.DescribeStackEvents("MyStack", "")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
t1, _ := time.Parse(time.RFC3339, "2010-07-27T22:26:28Z")
|
||||
t2, _ := time.Parse(time.RFC3339, "2010-07-27T22:27:28Z")
|
||||
t3, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "DescribeStackEvents")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NextToken"), Equals, "")
|
||||
|
||||
// Response test
|
||||
expected := &cf.DescribeStackEventsResponse{
|
||||
StackEvents: []cf.StackEvent{
|
||||
{
|
||||
EventId: "Event-1-Id",
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MyStack",
|
||||
PhysicalResourceId: "MyStack_One",
|
||||
ResourceType: "AWS::CloudFormation::Stack",
|
||||
Timestamp: t1,
|
||||
ResourceStatus: "CREATE_IN_PROGRESS",
|
||||
ResourceStatusReason: "User initiated",
|
||||
},
|
||||
{
|
||||
EventId: "Event-2-Id",
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MyDBInstance",
|
||||
PhysicalResourceId: "MyStack_DB1",
|
||||
ResourceType: "AWS::SecurityGroup",
|
||||
Timestamp: t2,
|
||||
ResourceStatus: "CREATE_IN_PROGRESS",
|
||||
ResourceProperties: "{\"GroupDescription\":...}",
|
||||
},
|
||||
{
|
||||
EventId: "Event-3-Id",
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MySG1",
|
||||
PhysicalResourceId: "MyStack_SG1",
|
||||
ResourceType: "AWS::SecurityGroup",
|
||||
Timestamp: t3,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
},
|
||||
NextToken: "",
|
||||
RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestDescribeStackResource(c *C) {
|
||||
testServer.Response(200, nil, DescribeStackResourceResponse)
|
||||
|
||||
resp, err := s.cf.DescribeStackResource("MyStack", "MyDBInstance")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "DescribeStackResource")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("LogicalResourceId"), Equals, "MyDBInstance")
|
||||
t, _ := time.Parse(time.RFC3339, "2011-07-07T22:27:28Z")
|
||||
// Response test
|
||||
expected := &cf.DescribeStackResourceResponse{
|
||||
StackResourceDetail: cf.StackResourceDetail{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MyDBInstance",
|
||||
PhysicalResourceId: "MyStack_DB1",
|
||||
ResourceType: "AWS::RDS::DBInstance",
|
||||
LastUpdatedTimestamp: t,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestDescribeStackResources(c *C) {
|
||||
testServer.Response(200, nil, DescribeStackResourcesResponse)
|
||||
|
||||
resp, err := s.cf.DescribeStackResources("MyStack", "", "")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
t1, _ := time.Parse(time.RFC3339, "2010-07-27T22:27:28Z")
|
||||
t2, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "DescribeStackResources")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("PhysicalResourceId"), Equals, "")
|
||||
c.Assert(values.Get("LogicalResourceId"), Equals, "")
|
||||
|
||||
// Response test
|
||||
expected := &cf.DescribeStackResourcesResponse{
|
||||
StackResources: []cf.StackResource{
|
||||
{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MyDBInstance",
|
||||
PhysicalResourceId: "MyStack_DB1",
|
||||
ResourceType: "AWS::DBInstance",
|
||||
Timestamp: t1,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
LogicalResourceId: "MyAutoScalingGroup",
|
||||
PhysicalResourceId: "MyStack_ASG1",
|
||||
ResourceType: "AWS::AutoScalingGroup",
|
||||
Timestamp: t2,
|
||||
ResourceStatus: "CREATE_IN_PROGRESS",
|
||||
},
|
||||
},
|
||||
RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestDescribeStacks(c *C) {
|
||||
testServer.Response(200, nil, DescribeStacksResponse)
|
||||
|
||||
resp, err := s.cf.DescribeStacks("MyStack", "")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
t, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "DescribeStacks")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NextToken"), Equals, "")
|
||||
|
||||
// Response test
|
||||
expected := &cf.DescribeStacksResponse{
|
||||
Stacks: []cf.Stack{
|
||||
{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
|
||||
StackName: "MyStack",
|
||||
Description: "My Description",
|
||||
Capabilities: []string{"CAPABILITY_IAM"},
|
||||
NotificationARNs: []string{"arn:aws:sns:region-name:account-name:topic-name"},
|
||||
Parameters: []cf.Parameter{
|
||||
{
|
||||
ParameterKey: "MyKey",
|
||||
ParameterValue: "MyValue",
|
||||
},
|
||||
},
|
||||
Tags: []cf.Tag{
|
||||
{
|
||||
Key: "MyTagKey",
|
||||
Value: "MyTagValue",
|
||||
},
|
||||
},
|
||||
CreationTime: t,
|
||||
StackStatus: "CREATE_COMPLETE",
|
||||
DisableRollback: false,
|
||||
Outputs: []cf.Output{
|
||||
{
|
||||
Description: "ServerUrl",
|
||||
OutputKey: "StartPage",
|
||||
OutputValue: "http://my-load-balancer.amazonaws.com:80/index.html",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NextToken: "",
|
||||
RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestEstimateTemplateCost(c *C) {
|
||||
testServer.Response(200, nil, EstimateTemplateCostResponse)
|
||||
|
||||
resp, err := s.cf.EstimateTemplateCost(nil, "", "https://s3.amazonaws.com/cloudformation-samples-us-east-1/Drupal_Simple.template")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "EstimateTemplateCost")
|
||||
c.Assert(values.Get("TemplateBody"), Equals, "")
|
||||
c.Assert(values.Get("TemplateURL"), Equals, "https://s3.amazonaws.com/cloudformation-samples-us-east-1/Drupal_Simple.template")
|
||||
// Response test
|
||||
c.Assert(resp.Url, Equals, "http://calculator.s3.amazonaws.com/calc5.html?key=cf-2e351785-e821-450c-9d58-625e1e1ebfb6")
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestGetStackPolicy(c *C) {
|
||||
testServer.Response(200, nil, GetStackPolicyResponse)
|
||||
|
||||
resp, err := s.cf.GetStackPolicy("MyStack")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "GetStackPolicy")
|
||||
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
// Response test
|
||||
policy := `{
|
||||
"Statement" : [
|
||||
{
|
||||
"Effect" : "Deny",
|
||||
"Action" : "Update:*",
|
||||
"Principal" : "*",
|
||||
"Resource" : "LogicalResourceId/ProductionDatabase"
|
||||
},
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : "Update:*",
|
||||
"Principal" : "*",
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
}`
|
||||
c.Assert(resp.StackPolicyBody, Equals, policy)
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestGetTemplate(c *C) {
|
||||
testServer.Response(200, nil, GetTemplateResponse)
|
||||
|
||||
resp, err := s.cf.GetTemplate("MyStack")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "GetTemplate")
|
||||
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
// Response test
|
||||
templateBody := `{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
"Description" : "Simple example",
|
||||
"Resources" : {
|
||||
"MySQS" : {
|
||||
"Type" : "AWS::SQS::Queue",
|
||||
"Properties" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
c.Assert(resp.TemplateBody, Equals, templateBody)
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestListStackResources(c *C) {
|
||||
testServer.Response(200, nil, ListStackResourcesResponse)
|
||||
|
||||
resp, err := s.cf.ListStackResources("MyStack", "4dad1-32131da-d-31")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "ListStackResources")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NextToken"), Equals, "4dad1-32131da-d-31")
|
||||
|
||||
// Response test
|
||||
t1, _ := time.Parse(time.RFC3339, "2011-06-21T20:15:58Z")
|
||||
t2, _ := time.Parse(time.RFC3339, "2011-06-21T20:25:57Z")
|
||||
t3, _ := time.Parse(time.RFC3339, "2011-06-21T20:26:12Z")
|
||||
t4, _ := time.Parse(time.RFC3339, "2011-06-21T20:28:48Z")
|
||||
t5, _ := time.Parse(time.RFC3339, "2011-06-21T20:29:06Z")
|
||||
t6, _ := time.Parse(time.RFC3339, "2011-06-21T20:29:23Z")
|
||||
|
||||
expected := &cf.ListStackResourcesResponse{
|
||||
StackResourceSummaries: []cf.StackResourceSummary{
|
||||
{
|
||||
LogicalResourceId: "DBSecurityGroup",
|
||||
PhysicalResourceId: "gmarcteststack-dbsecuritygroup-1s5m0ez5lkk6w",
|
||||
ResourceType: "AWS::RDS::DBSecurityGroup",
|
||||
LastUpdatedTimestamp: t1,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
LogicalResourceId: "SampleDB",
|
||||
PhysicalResourceId: "MyStack-sampledb-ycwhk1v830lx",
|
||||
ResourceType: "AWS::RDS::DBInstance",
|
||||
LastUpdatedTimestamp: t2,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
LogicalResourceId: "SampleApplication",
|
||||
PhysicalResourceId: "MyStack-SampleApplication-1MKNASYR3RBQL",
|
||||
ResourceType: "AWS::ElasticBeanstalk::Application",
|
||||
LastUpdatedTimestamp: t3,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
LogicalResourceId: "SampleEnvironment",
|
||||
PhysicalResourceId: "myst-Samp-1AGU6ERZX6M3Q",
|
||||
ResourceType: "AWS::ElasticBeanstalk::Environment",
|
||||
LastUpdatedTimestamp: t4,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
LogicalResourceId: "AlarmTopic",
|
||||
PhysicalResourceId: "arn:aws:sns:us-east-1:803981987763:MyStack-AlarmTopic-SW4IQELG7RPJ",
|
||||
ResourceType: "AWS::SNS::Topic",
|
||||
LastUpdatedTimestamp: t5,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
{
|
||||
LogicalResourceId: "CPUAlarmHigh",
|
||||
PhysicalResourceId: "MyStack-CPUAlarmHigh-POBWQPDJA81F",
|
||||
ResourceType: "AWS::CloudWatch::Alarm",
|
||||
LastUpdatedTimestamp: t6,
|
||||
ResourceStatus: "CREATE_COMPLETE",
|
||||
},
|
||||
},
|
||||
NextToken: "",
|
||||
RequestId: "2d06e36c-ac1d-11e0-a958-f9382b6eb86b",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestListStacks(c *C) {
|
||||
testServer.Response(200, nil, ListStacksResponse)
|
||||
|
||||
resp, err := s.cf.ListStacks([]string{"CREATE_IN_PROGRESS", "DELETE_COMPLETE"}, "4dad1-32131da-d-31")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "ListStacks")
|
||||
c.Assert(values.Get("StackStatusFilter.member.1"), Equals, "CREATE_IN_PROGRESS")
|
||||
c.Assert(values.Get("StackStatusFilter.member.2"), Equals, "DELETE_COMPLETE")
|
||||
c.Assert(values.Get("NextToken"), Equals, "4dad1-32131da-d-31")
|
||||
|
||||
// Response test
|
||||
c1, _ := time.Parse(time.RFC3339, "2011-05-23T15:47:44Z")
|
||||
c2, _ := time.Parse(time.RFC3339, "2011-03-05T19:57:58Z")
|
||||
d2, _ := time.Parse(time.RFC3339, "2011-03-10T16:20:51Z")
|
||||
|
||||
expected := &cf.ListStacksResponse{
|
||||
StackSummaries: []cf.StackSummary{
|
||||
{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:1234567:stack/TestCreate1/aaaaa",
|
||||
StackName: "vpc1",
|
||||
StackStatus: "CREATE_IN_PROGRESS",
|
||||
CreationTime: c1,
|
||||
TemplateDescription: "Creates one EC2 instance and a load balancer.",
|
||||
},
|
||||
{
|
||||
StackId: "arn:aws:cloudformation:us-east-1:1234567:stack/TestDelete2/bbbbb",
|
||||
StackName: "WP1",
|
||||
StackStatus: "DELETE_COMPLETE",
|
||||
CreationTime: c2,
|
||||
DeletionTime: d2,
|
||||
TemplateDescription: "A simple basic Cloudformation Template.",
|
||||
},
|
||||
},
|
||||
NextToken: "",
|
||||
RequestId: "2d06e36c-ac1d-11e0-a958-f9382b6eb86b",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *S) TestSetStackPolicy(c *C) {
|
||||
testServer.Response(200, nil, SetStackPolicyResponse)
|
||||
|
||||
resp, err := s.cf.SetStackPolicy("MyStack", "[Stack Policy Document]", "")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "SetStackPolicy")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("StackPolicyBody"), Equals, "[Stack Policy Document]")
|
||||
c.Assert(values.Get("StackPolicyUrl"), Equals, "")
|
||||
// Response test
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
}
|
||||
|
||||
func (s *S) TestUpdateStack(c *C) {
|
||||
testServer.Response(200, nil, UpdateStackResponse)
|
||||
|
||||
stackParams := &cf.UpdateStackParams{
|
||||
Capabilities: []string{"CAPABILITY_IAM"},
|
||||
NotificationARNs: []string{"arn:aws:sns:us-east-1:1234567890:my-topic"},
|
||||
StackPolicyBody: "{PolicyBody}",
|
||||
StackPolicyDuringUpdateBody: "{PolicyDuringUpdateBody}",
|
||||
Parameters: []cf.Parameter{
|
||||
{
|
||||
ParameterKey: "AvailabilityZone",
|
||||
ParameterValue: "us-east-1a",
|
||||
},
|
||||
},
|
||||
UsePreviousTemplate: true,
|
||||
StackName: "MyStack",
|
||||
TemplateBody: "[Template Document]",
|
||||
}
|
||||
resp, err := s.cf.UpdateStack(stackParams)
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "UpdateStack")
|
||||
c.Assert(values.Get("StackName"), Equals, "MyStack")
|
||||
c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
|
||||
c.Assert(values.Get("TemplateBody"), Equals, "[Template Document]")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
|
||||
c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
|
||||
c.Assert(values.Get("Capabilities.member.1"), Equals, "CAPABILITY_IAM")
|
||||
c.Assert(values.Get("StackPolicyBody"), Equals, "{PolicyBody}")
|
||||
c.Assert(values.Get("StackPolicyDuringUpdateBody"), Equals, "{PolicyDuringUpdateBody}")
|
||||
c.Assert(values.Get("UsePreviousTemplate"), Equals, "true")
|
||||
|
||||
// Response test
|
||||
c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
|
||||
c.Assert(resp.StackId, Equals, "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83")
|
||||
}
|
||||
|
||||
func (s *S) TestValidateTemplate(c *C) {
|
||||
testServer.Response(200, nil, ValidateTemplateResponse)
|
||||
|
||||
resp, err := s.cf.ValidateTemplate("", "http://myTemplateRepository/TemplateOne.template")
|
||||
c.Assert(err, IsNil)
|
||||
values := testServer.WaitRequest().PostForm
|
||||
|
||||
// Post request test
|
||||
c.Assert(values.Get("Version"), Equals, "2010-05-15")
|
||||
c.Assert(values.Get("Action"), Equals, "ValidateTemplate")
|
||||
c.Assert(values.Get("TemplateURL"), Equals, "http://myTemplateRepository/TemplateOne.template")
|
||||
c.Assert(values.Get("TemplateBody"), Equals, "")
|
||||
|
||||
// Response test
|
||||
expected := &cf.ValidateTemplateResponse{
|
||||
Description: "Test",
|
||||
Capabilities: []string{"CAPABILITY_IAM"},
|
||||
Parameters: []cf.TemplateParameter{
|
||||
{
|
||||
NoEcho: false,
|
||||
ParameterKey: "InstanceType",
|
||||
Description: "Type of instance to launch",
|
||||
DefaultValue: "m1.small",
|
||||
},
|
||||
{
|
||||
NoEcho: false,
|
||||
ParameterKey: "WebServerPort",
|
||||
Description: "The TCP port for the Web Server",
|
||||
DefaultValue: "8888",
|
||||
},
|
||||
{
|
||||
NoEcho: false,
|
||||
ParameterKey: "KeyName",
|
||||
Description: "Name of an existing EC2 KeyPair to enable SSH access into the server",
|
||||
},
|
||||
},
|
||||
RequestId: "0be7b6e8-e4a0-11e0-a5bd-9f8d5a7dbc91",
|
||||
}
|
||||
c.Assert(resp, DeepEquals, expected)
|
||||
}
|
||||
371
vendor/github.com/goamz/goamz/cloudformation/responses_test.go
generated
vendored
Normal file
371
vendor/github.com/goamz/goamz/cloudformation/responses_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
package cloudformation_test
|
||||
|
||||
var CancelUpdateStackResponse = `
|
||||
<CancelUpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<CancelUpdateStackResult/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CancelUpdateStackResponse>
|
||||
`
|
||||
|
||||
var CreateStackResponse = `
|
||||
<CreateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<CreateStackResult>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
</CreateStackResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateStackResponse>
|
||||
`
|
||||
|
||||
var CreateStackWithInvalidParamsResponse = `
|
||||
<ErrorResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<Error>
|
||||
<Type>Sender</Type>
|
||||
<Code>ValidationError</Code>
|
||||
<Message>Either Template URL or Template Body must be specified.</Message>
|
||||
</Error>
|
||||
<RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
|
||||
</ErrorResponse>
|
||||
`
|
||||
|
||||
var DeleteStackResponse = `
|
||||
<DeleteStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<DeleteStackResult/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DeleteStackResponse>
|
||||
`
|
||||
var DescribeStackEventsResponse = `
|
||||
<DescribeStackEventsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<DescribeStackEventsResult>
|
||||
<StackEvents>
|
||||
<member>
|
||||
<EventId>Event-1-Id</EventId>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MyStack</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_One</PhysicalResourceId>
|
||||
<ResourceType>AWS::CloudFormation::Stack</ResourceType>
|
||||
<Timestamp>2010-07-27T22:26:28Z</Timestamp>
|
||||
<ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
|
||||
<ResourceStatusReason>User initiated</ResourceStatusReason>
|
||||
</member>
|
||||
<member>
|
||||
<EventId>Event-2-Id</EventId>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MyDBInstance</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
|
||||
<ResourceType>AWS::SecurityGroup</ResourceType>
|
||||
<Timestamp>2010-07-27T22:27:28Z</Timestamp>
|
||||
<ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
|
||||
<ResourceProperties>{"GroupDescription":...}</ResourceProperties>
|
||||
</member>
|
||||
<member>
|
||||
<EventId>Event-3-Id</EventId>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MySG1</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_SG1</PhysicalResourceId>
|
||||
<ResourceType>AWS::SecurityGroup</ResourceType>
|
||||
<Timestamp>2010-07-27T22:28:28Z</Timestamp>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
</member>
|
||||
</StackEvents>
|
||||
<NextToken/>
|
||||
</DescribeStackEventsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeStackEventsResponse>
|
||||
`
|
||||
|
||||
var DescribeStackResourceResponse = `
|
||||
<DescribeStackResourceResponse>
|
||||
<DescribeStackResourceResult>
|
||||
<StackResourceDetail>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MyDBInstance</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
|
||||
<ResourceType>AWS::RDS::DBInstance</ResourceType>
|
||||
<LastUpdatedTimestamp>2011-07-07T22:27:28Z</LastUpdatedTimestamp>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
</StackResourceDetail>
|
||||
</DescribeStackResourceResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeStackResourceResponse>
|
||||
`
|
||||
var DescribeStackResourcesResponse = `
|
||||
<DescribeStackResourcesResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<DescribeStackResourcesResult>
|
||||
<StackResources>
|
||||
<member>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MyDBInstance</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
|
||||
<ResourceType>AWS::DBInstance</ResourceType>
|
||||
<Timestamp>2010-07-27T22:27:28Z</Timestamp>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
</member>
|
||||
<member>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackName>MyStack</StackName>
|
||||
<LogicalResourceId>MyAutoScalingGroup</LogicalResourceId>
|
||||
<PhysicalResourceId>MyStack_ASG1</PhysicalResourceId>
|
||||
<ResourceType>AWS::AutoScalingGroup</ResourceType>
|
||||
<Timestamp>2010-07-27T22:28:28Z</Timestamp>
|
||||
<ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
|
||||
</member>
|
||||
</StackResources>
|
||||
</DescribeStackResourcesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeStackResourcesResponse>
|
||||
`
|
||||
|
||||
var DescribeStacksResponse = `
|
||||
<DescribeStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<DescribeStacksResult>
|
||||
<Stacks>
|
||||
<member>
|
||||
<StackName>MyStack</StackName>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
<StackStatusReason/>
|
||||
<Description>My Description</Description>
|
||||
<Capabilities>
|
||||
<member>CAPABILITY_IAM</member>
|
||||
</Capabilities>
|
||||
<NotificationARNs>
|
||||
<member>arn:aws:sns:region-name:account-name:topic-name</member>
|
||||
</NotificationARNs>
|
||||
<Parameters>
|
||||
<member>
|
||||
<ParameterValue>MyValue</ParameterValue>
|
||||
<ParameterKey>MyKey</ParameterKey>
|
||||
</member>
|
||||
</Parameters>
|
||||
<Tags>
|
||||
<member>
|
||||
<Key>MyTagKey</Key>
|
||||
<Value>MyTagValue</Value>
|
||||
</member>
|
||||
</Tags>
|
||||
<CreationTime>2010-07-27T22:28:28Z</CreationTime>
|
||||
<StackStatus>CREATE_COMPLETE</StackStatus>
|
||||
<DisableRollback>false</DisableRollback>
|
||||
<Outputs>
|
||||
<member>
|
||||
<Description>ServerUrl</Description>
|
||||
<OutputKey>StartPage</OutputKey>
|
||||
<OutputValue>http://my-load-balancer.amazonaws.com:80/index.html</OutputValue>
|
||||
</member>
|
||||
</Outputs>
|
||||
</member>
|
||||
</Stacks>
|
||||
<NextToken/>
|
||||
</DescribeStacksResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DescribeStacksResponse>
|
||||
`
|
||||
|
||||
var EstimateTemplateCostResponse = `
|
||||
<EstimateTemplateCostResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<EstimateTemplateCostResult>
|
||||
<Url>http://calculator.s3.amazonaws.com/calc5.html?key=cf-2e351785-e821-450c-9d58-625e1e1ebfb6</Url>
|
||||
</EstimateTemplateCostResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</EstimateTemplateCostResponse>
|
||||
`
|
||||
|
||||
var GetStackPolicyResponse = `
|
||||
<GetStackPolicyResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<GetStackPolicyResult>
|
||||
<StackPolicyBody>{
|
||||
"Statement" : [
|
||||
{
|
||||
"Effect" : "Deny",
|
||||
"Action" : "Update:*",
|
||||
"Principal" : "*",
|
||||
"Resource" : "LogicalResourceId/ProductionDatabase"
|
||||
},
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : "Update:*",
|
||||
"Principal" : "*",
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
}</StackPolicyBody>
|
||||
</GetStackPolicyResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</GetStackPolicyResponse>
|
||||
`
|
||||
|
||||
var GetTemplateResponse = `
|
||||
<GetTemplateResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<GetTemplateResult>
|
||||
<TemplateBody>{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
"Description" : "Simple example",
|
||||
"Resources" : {
|
||||
"MySQS" : {
|
||||
"Type" : "AWS::SQS::Queue",
|
||||
"Properties" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}</TemplateBody>
|
||||
</GetTemplateResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</GetTemplateResponse>
|
||||
`
|
||||
|
||||
var ListStackResourcesResponse = `
|
||||
<ListStackResourcesResponse>
|
||||
<ListStackResourcesResult>
|
||||
<StackResourceSummaries>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>DBSecurityGroup</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:15:58Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>gmarcteststack-dbsecuritygroup-1s5m0ez5lkk6w</PhysicalResourceId>
|
||||
<ResourceType>AWS::RDS::DBSecurityGroup</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>SampleDB</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:25:57Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>MyStack-sampledb-ycwhk1v830lx</PhysicalResourceId>
|
||||
<ResourceType>AWS::RDS::DBInstance</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>SampleApplication</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:26:12Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>MyStack-SampleApplication-1MKNASYR3RBQL</PhysicalResourceId>
|
||||
<ResourceType>AWS::ElasticBeanstalk::Application</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>SampleEnvironment</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:28:48Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>myst-Samp-1AGU6ERZX6M3Q</PhysicalResourceId>
|
||||
<ResourceType>AWS::ElasticBeanstalk::Environment</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>AlarmTopic</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:29:06Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>arn:aws:sns:us-east-1:803981987763:MyStack-AlarmTopic-SW4IQELG7RPJ</PhysicalResourceId>
|
||||
<ResourceType>AWS::SNS::Topic</ResourceType>
|
||||
</member>
|
||||
<member>
|
||||
<ResourceStatus>CREATE_COMPLETE</ResourceStatus>
|
||||
<LogicalResourceId>CPUAlarmHigh</LogicalResourceId>
|
||||
<LastUpdatedTimestamp>2011-06-21T20:29:23Z</LastUpdatedTimestamp>
|
||||
<PhysicalResourceId>MyStack-CPUAlarmHigh-POBWQPDJA81F</PhysicalResourceId>
|
||||
<ResourceType>AWS::CloudWatch::Alarm</ResourceType>
|
||||
</member>
|
||||
</StackResourceSummaries>
|
||||
</ListStackResourcesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>2d06e36c-ac1d-11e0-a958-f9382b6eb86b</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListStackResourcesResponse>
|
||||
`
|
||||
|
||||
var ListStacksResponse = `
|
||||
<ListStacksResponse>
|
||||
<ListStacksResult>
|
||||
<StackSummaries>
|
||||
<member>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:1234567:stack/TestCreate1/aaaaa</StackId>
|
||||
<StackStatus>CREATE_IN_PROGRESS</StackStatus>
|
||||
<StackName>vpc1</StackName>
|
||||
<CreationTime>2011-05-23T15:47:44Z</CreationTime>
|
||||
<TemplateDescription>Creates one EC2 instance and a load balancer.</TemplateDescription>
|
||||
</member>
|
||||
<member>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:1234567:stack/TestDelete2/bbbbb</StackId>
|
||||
<StackStatus>DELETE_COMPLETE</StackStatus>
|
||||
<DeletionTime>2011-03-10T16:20:51Z</DeletionTime>
|
||||
<StackName>WP1</StackName>
|
||||
<CreationTime>2011-03-05T19:57:58Z</CreationTime>
|
||||
<TemplateDescription>A simple basic Cloudformation Template.</TemplateDescription>
|
||||
</member>
|
||||
</StackSummaries>
|
||||
</ListStacksResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>2d06e36c-ac1d-11e0-a958-f9382b6eb86b</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListStacksResponse>
|
||||
`
|
||||
|
||||
var SetStackPolicyResponse = `
|
||||
<SetStackPolicyResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<SetStackPolicyResponse/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</SetStackPolicyResponse>
|
||||
`
|
||||
|
||||
var UpdateStackResponse = `
|
||||
<UpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<UpdateStackResult>
|
||||
<StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
|
||||
</UpdateStackResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</UpdateStackResponse>
|
||||
`
|
||||
var ValidateTemplateResponse = `
|
||||
<ValidateTemplateResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<ValidateTemplateResult>
|
||||
<Description>Test</Description>
|
||||
<Capabilities>
|
||||
<member>CAPABILITY_IAM</member>
|
||||
</Capabilities>
|
||||
<Parameters>
|
||||
<member>
|
||||
<NoEcho>false</NoEcho>
|
||||
<ParameterKey>InstanceType</ParameterKey>
|
||||
<Description>Type of instance to launch</Description>
|
||||
<DefaultValue>m1.small</DefaultValue>
|
||||
</member>
|
||||
<member>
|
||||
<NoEcho>false</NoEcho>
|
||||
<ParameterKey>WebServerPort</ParameterKey>
|
||||
<Description>The TCP port for the Web Server</Description>
|
||||
<DefaultValue>8888</DefaultValue>
|
||||
</member>
|
||||
<member>
|
||||
<NoEcho>false</NoEcho>
|
||||
<ParameterKey>KeyName</ParameterKey>
|
||||
<Description>Name of an existing EC2 KeyPair to enable SSH access into the server</Description>
|
||||
</member>
|
||||
</Parameters>
|
||||
</ValidateTemplateResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>0be7b6e8-e4a0-11e0-a5bd-9f8d5a7dbc91</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ValidateTemplateResponse>
|
||||
`
|
||||
135
vendor/github.com/goamz/goamz/cloudfront/cloudfront.go
generated
vendored
Normal file
135
vendor/github.com/goamz/goamz/cloudfront/cloudfront.go
generated
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package cloudfront
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CloudFront struct {
|
||||
BaseURL string
|
||||
keyPairId string
|
||||
key *rsa.PrivateKey
|
||||
}
|
||||
|
||||
var base64Replacer = strings.NewReplacer("=", "_", "+", "-", "/", "~")
|
||||
|
||||
func New(baseurl string, key *rsa.PrivateKey, keyPairId string) *CloudFront {
|
||||
return &CloudFront{
|
||||
BaseURL: baseurl,
|
||||
keyPairId: keyPairId,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
type epochTime struct {
|
||||
EpochTime int64 `json:"AWS:EpochTime"`
|
||||
}
|
||||
|
||||
type condition struct {
|
||||
DateLessThan epochTime
|
||||
}
|
||||
|
||||
type statement struct {
|
||||
Resource string
|
||||
Condition condition
|
||||
}
|
||||
|
||||
type policy struct {
|
||||
Statement []statement
|
||||
}
|
||||
|
||||
func buildPolicy(resource string, expireTime time.Time) ([]byte, error) {
|
||||
p := &policy{
|
||||
Statement: []statement{
|
||||
statement{
|
||||
Resource: resource,
|
||||
Condition: condition{
|
||||
DateLessThan: epochTime{
|
||||
EpochTime: expireTime.Truncate(time.Millisecond).Unix(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
func (cf *CloudFront) generateSignature(policy []byte) (string, error) {
|
||||
hash := sha1.New()
|
||||
if _, err := hash.Write(policy); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hashed := hash.Sum(nil)
|
||||
|
||||
signed, err := rsa.SignPKCS1v15(rand.Reader, cf.key, crypto.SHA1, hashed)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
encoded := base64Replacer.Replace(base64.StdEncoding.EncodeToString(signed))
|
||||
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
// Creates a signed url using RSAwithSHA1 as specified by
|
||||
// http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html#private-content-canned-policy-creating-signature
|
||||
func (cf *CloudFront) CannedSignedURL(path, queryString string, expires time.Time) (string, error) {
|
||||
resource := cf.BaseURL + path
|
||||
if queryString != "" {
|
||||
resource = path + "?" + queryString
|
||||
}
|
||||
|
||||
policy, err := buildPolicy(resource, expires)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
signature, err := cf.generateSignature(policy)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// TOOD: Do this once
|
||||
uri, err := url.Parse(cf.BaseURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
uri.RawQuery = queryString
|
||||
if queryString != "" {
|
||||
uri.RawQuery += "&"
|
||||
}
|
||||
|
||||
expireTime := expires.Truncate(time.Millisecond).Unix()
|
||||
|
||||
uri.Path = path
|
||||
uri.RawQuery += fmt.Sprintf("Expires=%d&Signature=%s&Key-Pair-Id=%s", expireTime, signature, cf.keyPairId)
|
||||
|
||||
return uri.String(), nil
|
||||
}
|
||||
|
||||
func (cloudfront *CloudFront) SignedURL(path, querystrings string, expires time.Time) string {
|
||||
policy := `{"Statement":[{"Resource":"` + path + "?" + querystrings + `,"Condition":{"DateLessThan":{"AWS:EpochTime":` + strconv.FormatInt(expires.Truncate(time.Millisecond).Unix(), 10) + `}}}]}`
|
||||
|
||||
hash := sha1.New()
|
||||
hash.Write([]byte(policy))
|
||||
b := hash.Sum(nil)
|
||||
he := base64.StdEncoding.EncodeToString(b)
|
||||
|
||||
policySha1 := he
|
||||
|
||||
url := cloudfront.BaseURL + path + "?" + querystrings + "&Expires=" + strconv.FormatInt(expires.Unix(), 10) + "&Signature=" + policySha1 + "&Key-Pair-Id=" + cloudfront.keyPairId
|
||||
|
||||
return url
|
||||
}
|
||||
52
vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go
generated
vendored
Normal file
52
vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package cloudfront
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSignedCannedURL(t *testing.T) {
|
||||
rawKey, err := ioutil.ReadFile("testdata/key.pem")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pemKey, _ := pem.Decode(rawKey)
|
||||
privateKey, err := x509.ParsePKCS1PrivateKey(pemKey.Bytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cf := &CloudFront{
|
||||
key: privateKey,
|
||||
keyPairId: "test-key-pair-1231245",
|
||||
BaseURL: "https://cloudfront.com",
|
||||
}
|
||||
|
||||
expireTime, err := time.Parse(time.RFC3339, "2014-03-28T14:00:21Z")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
query := make(url.Values)
|
||||
query.Add("test", "value")
|
||||
|
||||
uri, err := cf.CannedSignedURL("test", "test=value", expireTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signature := parsed.Query().Get("Signature")
|
||||
if signature == "" {
|
||||
t.Fatal("Encoded signature is empty")
|
||||
}
|
||||
}
|
||||
15
vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem
generated
vendored
Normal file
15
vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQC0yMzp9DkPAE99DhsEaGkqougLvtmDKri4bZj0fFjmGmjyyjz9
|
||||
hlrsr87LHVWzH/7igK7040HG1UqypX3ijtJa9+6BKHwBBctboU3y4GfwFwVAOumY
|
||||
9UytFpyPlgUFrffZLQAywKkT24OgcfEj0G5kiQn760wFnmSUtOuITo708QIDAQAB
|
||||
AoGAJUA6+PoZx72Io3wElSPuh5qJteHdb+mdpmLu4XG936wRc/W4G4VTtvGC6tdg
|
||||
kUhGfOWHJ26sXwwUGDuBdO146m0DkBTuIooy97afpL6hXgL5v4ELHbbuFJcf4Geg
|
||||
/UAuexvRT1HenYFQ/iXM0LlqI33i8cFRc1A+j0Gseo07gAECQQDYFCn7OUokX+Q8
|
||||
M2Cwhu7JT1obmP2HwsBtXl0CDDxtOQkuYJP/UqvtdYPz/kRn3yQjoynaCTHYrFz/
|
||||
H8oN1nNhAkEA1i9TEpo7RbanIyT4vbc1/5xfjE7Pj0lnGku0QXFp/S+8YxbqhjrQ
|
||||
4Qp7TTXIPPqvQhhEpAGGspM460K3F6h7kQJBANJCbMeFa9wRY2ohJIkiA+HoUWph
|
||||
aPNeUxkZpa+EcJhn08NJPzpIG/ypSYl3duEMhYIYF3WPVO3ea2/mYxsr/oECQFj5
|
||||
td/fdEoEk7AU1sQxDNyPwF2QC8dxbcRNuKcLD0Wfg/oB9hEm88jYytoLQpCabx3c
|
||||
6P7cp3EdmaKZx2erlRECQDYTSK2tS0+VoXSV9JbU08Pbu53j3Zhmp4l0csP+l7EU
|
||||
U+rRQzKho4X9vpR/VpRGXbw8tTIhojNpHh5ofryVfgk=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
6
vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub
generated
vendored
Normal file
6
vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0yMzp9DkPAE99DhsEaGkqougL
|
||||
vtmDKri4bZj0fFjmGmjyyjz9hlrsr87LHVWzH/7igK7040HG1UqypX3ijtJa9+6B
|
||||
KHwBBctboU3y4GfwFwVAOumY9UytFpyPlgUFrffZLQAywKkT24OgcfEj0G5kiQn7
|
||||
60wFnmSUtOuITo708QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
7
vendor/github.com/goamz/goamz/cloudwatch/ChangeLog
generated
vendored
Normal file
7
vendor/github.com/goamz/goamz/cloudwatch/ChangeLog
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
2013-10-21 Carlos Salguero <cfsalguero@gmail.com>
|
||||
|
||||
* Removed Namespace from the constructor as not all AWS API method needs it
|
||||
and methods like ListMetrics you could need to call the method without a
|
||||
Namespace to list all available metrics
|
||||
|
||||
* Added ListMetrics method
|
||||
109
vendor/github.com/goamz/goamz/cloudwatch/README.md
generated
vendored
Normal file
109
vendor/github.com/goamz/goamz/cloudwatch/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#GoLang AWS Cloudwatch
|
||||
|
||||
## Installation
|
||||
Please refer to the project's main page at [https://github.com/goamz/goamz](https://github.com/goamz/goamz) for instructions about how to install.
|
||||
|
||||
## Available methods
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>GetMetricStatistics</td>
|
||||
<td>Gets statistics for the specified metric.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ListMetrics</td>
|
||||
<td>Returns a list of valid metrics stored for the AWS account.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PutMetricData</td>
|
||||
<td>Publishes metric data points to Amazon CloudWatch.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PutMetricAlarm</td>
|
||||
<td>Creates or updates an alarm and associates it with the specified Amazon CloudWatch metric.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Please refer to AWS Cloudwatch's documentation for more info](http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Operations.html)
|
||||
|
||||
##Examples
|
||||
####Get Metric Statistics
|
||||
|
||||
```
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"os"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"github.com/goamz/goamz/cloudwatch"
|
||||
)
|
||||
|
||||
func test_get_metric_statistics() {
|
||||
region := aws.Regions["a_region"]
|
||||
namespace:= "AWS/ELB"
|
||||
dimension := &cloudwatch.Dimension{
|
||||
Name: "LoadBalancerName",
|
||||
Value: "your_value",
|
||||
}
|
||||
metricName := "RequestCount"
|
||||
now := time.Now()
|
||||
prev := now.Add(time.Duration(600)*time.Second*-1) // 600 secs = 10 minutes
|
||||
|
||||
auth, err := aws.GetAuth("your_AccessKeyId", "your_SecretAccessKey", "", now)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cw, err := cloudwatch.NewCloudWatch(auth, region.CloudWatchServicepoint)
|
||||
request := &cloudwatch.GetMetricStatisticsRequest {
|
||||
Dimensions: []cloudwatch.Dimension{*dimension},
|
||||
EndTime: now,
|
||||
StartTime: prev,
|
||||
MetricName: metricName,
|
||||
Unit: "Count", // Not mandatory
|
||||
Period: 60,
|
||||
Statistics: []string{"Sum"},
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
response, err := cw.GetMetricStatistics(request)
|
||||
if err == nil {
|
||||
fmt.Printf("%+v\n", response)
|
||||
} else {
|
||||
fmt.Printf("Error: %+v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
####List Metrics
|
||||
|
||||
```
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"os"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"github.com/goamz/goamz/cloudwatch"
|
||||
)
|
||||
|
||||
func test_list_metrics() {
|
||||
region := aws.Regions["us-east-1"] // Any region here
|
||||
now := time.Now()
|
||||
|
||||
auth, err := aws.GetAuth("an AccessKeyId", "a SecretAccessKey", "", now)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cw, err := cloudwatch.NewCloudWatch(auth, region.CloudWatchServicepoint)
|
||||
request := &cloudwatch.ListMetricsRequest{Namespace: "AWS/EC2"}
|
||||
|
||||
response, err := cw.ListMetrics(request)
|
||||
if err == nil {
|
||||
fmt.Printf("%+v\n", response)
|
||||
} else {
|
||||
fmt.Printf("Error: %+v\n", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
404
vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go
generated
vendored
Normal file
404
vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go
generated
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
/***** BEGIN LICENSE BLOCK *****
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2012
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Ben Bangert (bbangert@mozilla.com)
|
||||
# Logan Owen (lsowen@s1network.com)
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****/
|
||||
|
||||
package cloudwatch
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/feyeleanor/sets"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The CloudWatch type encapsulates all the CloudWatch operations in a region.
|
||||
type CloudWatch struct {
|
||||
Service aws.AWSService
|
||||
}
|
||||
|
||||
type Dimension struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type StatisticSet struct {
|
||||
Maximum float64
|
||||
Minimum float64
|
||||
SampleCount float64
|
||||
Sum float64
|
||||
}
|
||||
|
||||
type MetricDatum struct {
|
||||
Dimensions []Dimension
|
||||
MetricName string
|
||||
StatisticValues *StatisticSet
|
||||
Timestamp time.Time
|
||||
Unit string
|
||||
Value float64
|
||||
}
|
||||
|
||||
type Datapoint struct {
|
||||
Average float64
|
||||
Maximum float64
|
||||
Minimum float64
|
||||
SampleCount float64
|
||||
Sum float64
|
||||
Timestamp time.Time
|
||||
Unit string
|
||||
}
|
||||
|
||||
type GetMetricStatisticsRequest struct {
|
||||
Dimensions []Dimension
|
||||
EndTime time.Time
|
||||
StartTime time.Time
|
||||
MetricName string
|
||||
Unit string
|
||||
Period int
|
||||
Statistics []string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type GetMetricStatisticsResult struct {
|
||||
Datapoints []Datapoint `xml:"Datapoints>member"`
|
||||
NextToken string `xml:"NextToken"`
|
||||
}
|
||||
|
||||
type GetMetricStatisticsResponse struct {
|
||||
GetMetricStatisticsResult GetMetricStatisticsResult
|
||||
ResponseMetadata aws.ResponseMetadata
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
Dimensions []Dimension `xml:"Dimensions>member"`
|
||||
MetricName string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type ListMetricsResult struct {
|
||||
Metrics []Metric `xml:"Metrics>member"`
|
||||
NextToken string
|
||||
}
|
||||
|
||||
type ListMetricsResponse struct {
|
||||
ListMetricsResult ListMetricsResult
|
||||
ResponseMetadata aws.ResponseMetadata
|
||||
}
|
||||
|
||||
type ListMetricsRequest struct {
|
||||
Dimensions []Dimension
|
||||
MetricName string
|
||||
Namespace string
|
||||
NextToken string
|
||||
}
|
||||
|
||||
type AlarmAction struct {
|
||||
ARN string
|
||||
}
|
||||
|
||||
type MetricAlarm struct {
|
||||
AlarmActions []AlarmAction
|
||||
AlarmDescription string
|
||||
AlarmName string
|
||||
ComparisonOperator string
|
||||
Dimensions []Dimension
|
||||
EvaluationPeriods int
|
||||
InsufficientDataActions []AlarmAction
|
||||
MetricName string
|
||||
Namespace string
|
||||
OkActions []AlarmAction
|
||||
Period int
|
||||
Statistic string
|
||||
Threshold float64
|
||||
Unit string
|
||||
}
|
||||
|
||||
var attempts = aws.AttemptStrategy{
|
||||
Min: 5,
|
||||
Total: 5 * time.Second,
|
||||
Delay: 200 * time.Millisecond,
|
||||
}
|
||||
|
||||
var validUnits = sets.SSet(
|
||||
"Seconds",
|
||||
"Microseconds",
|
||||
"Milliseconds",
|
||||
"Bytes",
|
||||
"Kilobytes",
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terabytes",
|
||||
"Bits",
|
||||
"Kilobits",
|
||||
"Megabits",
|
||||
"Gigabits",
|
||||
"Terabits",
|
||||
"Percent",
|
||||
"Count",
|
||||
"Bytes/Second",
|
||||
"Kilobytes/Second",
|
||||
"Megabytes/Second",
|
||||
"Gigabytes/Second",
|
||||
"Terabytes/Second",
|
||||
"Bits/Second",
|
||||
"Kilobits/Second",
|
||||
"Megabits/Second",
|
||||
"Gigabits/Second",
|
||||
"Terabits/Second",
|
||||
"Count/Second",
|
||||
)
|
||||
|
||||
var validMetricStatistics = sets.SSet(
|
||||
"Average",
|
||||
"Sum",
|
||||
"SampleCount",
|
||||
"Maximum",
|
||||
"Minimum",
|
||||
)
|
||||
|
||||
var validComparisonOperators = sets.SSet(
|
||||
"LessThanThreshold",
|
||||
"LessThanOrEqualToThreshold",
|
||||
"GreaterThanThreshold",
|
||||
"GreaterThanOrEqualToThreshold",
|
||||
)
|
||||
|
||||
// Create a new CloudWatch object for a given namespace
|
||||
func NewCloudWatch(auth aws.Auth, region aws.ServiceInfo) (*CloudWatch, error) {
|
||||
service, err := aws.NewService(auth, region)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CloudWatch{
|
||||
Service: service,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CloudWatch) query(method, path string, params map[string]string, resp interface{}) error {
|
||||
// Add basic Cloudwatch param
|
||||
params["Version"] = "2010-08-01"
|
||||
|
||||
r, err := c.Service.Query(method, path, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
if r.StatusCode != 200 {
|
||||
return c.Service.BuildError(r)
|
||||
}
|
||||
err = xml.NewDecoder(r.Body).Decode(resp)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get statistics for specified metric
|
||||
//
|
||||
// If the arguments are invalid or the server returns an error, the error will
|
||||
// be set and the other values undefined.
|
||||
func (c *CloudWatch) GetMetricStatistics(req *GetMetricStatisticsRequest) (result *GetMetricStatisticsResponse, err error) {
|
||||
statisticsSet := sets.SSet(req.Statistics...)
|
||||
// Kick out argument errors
|
||||
switch {
|
||||
case req.EndTime.IsZero():
|
||||
err = errors.New("No endTime specified")
|
||||
case req.StartTime.IsZero():
|
||||
err = errors.New("No startTime specified")
|
||||
case req.MetricName == "":
|
||||
err = errors.New("No metricName specified")
|
||||
case req.Namespace == "":
|
||||
err = errors.New("No Namespace specified")
|
||||
case req.Period < 60 || req.Period%60 != 0:
|
||||
err = errors.New("Period not 60 seconds or a multiple of 60 seconds")
|
||||
case len(req.Statistics) < 1:
|
||||
err = errors.New("No statistics supplied")
|
||||
case validMetricStatistics.Union(statisticsSet).Len() != validMetricStatistics.Len():
|
||||
err = errors.New("Invalid statistic values supplied")
|
||||
case req.Unit != "" && !validUnits.Member(req.Unit):
|
||||
err = errors.New("Unit is not a valid value")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Serialize all the params
|
||||
params := aws.MakeParams("GetMetricStatistics")
|
||||
params["EndTime"] = req.EndTime.UTC().Format(time.RFC3339)
|
||||
params["StartTime"] = req.StartTime.UTC().Format(time.RFC3339)
|
||||
params["MetricName"] = req.MetricName
|
||||
params["Namespace"] = req.Namespace
|
||||
params["Period"] = strconv.Itoa(req.Period)
|
||||
if req.Unit != "" {
|
||||
params["Unit"] = req.Unit
|
||||
}
|
||||
|
||||
// Serialize the lists of data
|
||||
for i, d := range req.Dimensions {
|
||||
prefix := "Dimensions.member." + strconv.Itoa(i+1)
|
||||
params[prefix+".Name"] = d.Name
|
||||
params[prefix+".Value"] = d.Value
|
||||
}
|
||||
for i, d := range req.Statistics {
|
||||
prefix := "Statistics.member." + strconv.Itoa(i+1)
|
||||
params[prefix] = d
|
||||
}
|
||||
result = new(GetMetricStatisticsResponse)
|
||||
err = c.query("GET", "/", params, result)
|
||||
return
|
||||
}
|
||||
|
||||
// Returns a list of valid metrics stored for the AWS account owner.
|
||||
// Returned metrics can be used with GetMetricStatistics to obtain statistical data for a given metric.
|
||||
|
||||
func (c *CloudWatch) ListMetrics(req *ListMetricsRequest) (result *ListMetricsResponse, err error) {
|
||||
|
||||
// Serialize all the params
|
||||
params := aws.MakeParams("ListMetrics")
|
||||
if req.Namespace != "" {
|
||||
params["Namespace"] = req.Namespace
|
||||
}
|
||||
if len(req.Dimensions) > 0 {
|
||||
for i, d := range req.Dimensions {
|
||||
prefix := "Dimensions.member." + strconv.Itoa(i+1)
|
||||
params[prefix+".Name"] = d.Name
|
||||
params[prefix+".Value"] = d.Value
|
||||
}
|
||||
}
|
||||
|
||||
result = new(ListMetricsResponse)
|
||||
err = c.query("GET", "/", params, &result)
|
||||
metrics := result.ListMetricsResult.Metrics
|
||||
if result.ListMetricsResult.NextToken != "" {
|
||||
params = aws.MakeParams("ListMetrics")
|
||||
params["NextToken"] = result.ListMetricsResult.NextToken
|
||||
for result.ListMetricsResult.NextToken != "" && err == nil {
|
||||
result = new(ListMetricsResponse)
|
||||
err = c.query("GET", "/", params, &result)
|
||||
if err == nil {
|
||||
newslice := make([]Metric, len(metrics)+len(result.ListMetricsResult.Metrics))
|
||||
copy(newslice, metrics)
|
||||
copy(newslice[len(metrics):], result.ListMetricsResult.Metrics)
|
||||
metrics = newslice
|
||||
}
|
||||
}
|
||||
result.ListMetricsResult.Metrics = metrics
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *CloudWatch) PutMetricData(metrics []MetricDatum) (result *aws.BaseResponse, err error) {
|
||||
return c.PutMetricDataNamespace(metrics, "")
|
||||
}
|
||||
|
||||
func (c *CloudWatch) PutMetricDataNamespace(metrics []MetricDatum, namespace string) (result *aws.BaseResponse, err error) {
|
||||
// Serialize the params
|
||||
params := aws.MakeParams("PutMetricData")
|
||||
if namespace != "" {
|
||||
params["Namespace"] = namespace
|
||||
}
|
||||
for i, metric := range metrics {
|
||||
prefix := "MetricData.member." + strconv.Itoa(i+1)
|
||||
if metric.MetricName == "" {
|
||||
err = fmt.Errorf("No metric name supplied for metric: %d", i)
|
||||
return
|
||||
}
|
||||
params[prefix+".MetricName"] = metric.MetricName
|
||||
if metric.Unit != "" {
|
||||
params[prefix+".Unit"] = metric.Unit
|
||||
}
|
||||
params[prefix+".Value"] = strconv.FormatFloat(metric.Value, 'E', 10, 64)
|
||||
if !metric.Timestamp.IsZero() {
|
||||
params[prefix+".Timestamp"] = metric.Timestamp.UTC().Format(time.RFC3339)
|
||||
}
|
||||
for j, dim := range metric.Dimensions {
|
||||
dimprefix := prefix + ".Dimensions.member." + strconv.Itoa(j+1)
|
||||
params[dimprefix+".Name"] = dim.Name
|
||||
params[dimprefix+".Value"] = dim.Value
|
||||
}
|
||||
if metric.StatisticValues != nil {
|
||||
statprefix := prefix + ".StatisticValues"
|
||||
params[statprefix+".Maximum"] = strconv.FormatFloat(metric.StatisticValues.Maximum, 'E', 10, 64)
|
||||
params[statprefix+".Minimum"] = strconv.FormatFloat(metric.StatisticValues.Minimum, 'E', 10, 64)
|
||||
params[statprefix+".SampleCount"] = strconv.FormatFloat(metric.StatisticValues.SampleCount, 'E', 10, 64)
|
||||
params[statprefix+".Sum"] = strconv.FormatFloat(metric.StatisticValues.Sum, 'E', 10, 64)
|
||||
}
|
||||
}
|
||||
result = new(aws.BaseResponse)
|
||||
err = c.query("POST", "/", params, result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *CloudWatch) PutMetricAlarm(alarm *MetricAlarm) (result *aws.BaseResponse, err error) {
|
||||
// Serialize the params
|
||||
params := aws.MakeParams("PutMetricAlarm")
|
||||
|
||||
switch {
|
||||
case alarm.AlarmName == "":
|
||||
err = errors.New("No AlarmName supplied")
|
||||
case !validComparisonOperators.Member(alarm.ComparisonOperator):
|
||||
err = errors.New("ComparisonOperator is not valid")
|
||||
case alarm.EvaluationPeriods == 0:
|
||||
err = errors.New("No number of EvaluationPeriods specified")
|
||||
case alarm.MetricName == "":
|
||||
err = errors.New("No MetricName specified")
|
||||
case alarm.Namespace == "":
|
||||
err = errors.New("No Namespace specified")
|
||||
case alarm.Period == 0:
|
||||
err = errors.New("No Period over which statistic should apply was specified")
|
||||
case !validMetricStatistics.Member(alarm.Statistic):
|
||||
err = errors.New("Invalid statistic value supplied")
|
||||
case alarm.Threshold == 0:
|
||||
err = errors.New("No Threshold value specified")
|
||||
case alarm.Unit != "" && !validUnits.Member(alarm.Unit):
|
||||
err = errors.New("Unit is not a valid value")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, action := range alarm.AlarmActions {
|
||||
params["AlarmActions.member."+strconv.Itoa(i+1)] = action.ARN
|
||||
}
|
||||
for i, action := range alarm.InsufficientDataActions {
|
||||
params["InsufficientDataActions.member."+strconv.Itoa(i+1)] = action.ARN
|
||||
}
|
||||
for i, action := range alarm.OkActions {
|
||||
params["OKActions.member."+strconv.Itoa(i+1)] = action.ARN
|
||||
}
|
||||
if alarm.AlarmDescription != "" {
|
||||
params["AlarmDescription"] = alarm.AlarmDescription
|
||||
}
|
||||
params["AlarmDescription"] = alarm.AlarmDescription
|
||||
params["AlarmName"] = alarm.AlarmName
|
||||
params["ComparisonOperator"] = alarm.ComparisonOperator
|
||||
for i, dim := range alarm.Dimensions {
|
||||
dimprefix := "Dimensions.member." + strconv.Itoa(i+1)
|
||||
params[dimprefix+".Name"] = dim.Name
|
||||
params[dimprefix+".Value"] = dim.Value
|
||||
}
|
||||
params["EvaluationPeriods"] = strconv.Itoa(alarm.EvaluationPeriods)
|
||||
params["MetricName"] = alarm.MetricName
|
||||
params["Namespace"] = alarm.Namespace
|
||||
params["Period"] = strconv.Itoa(alarm.Period)
|
||||
params["Statistic"] = alarm.Statistic
|
||||
params["Threshold"] = strconv.FormatFloat(alarm.Threshold, 'E', 10, 64)
|
||||
if alarm.Unit != "" {
|
||||
params["Unit"] = alarm.Unit
|
||||
}
|
||||
|
||||
result = new(aws.BaseResponse)
|
||||
err = c.query("POST", "/", params, result)
|
||||
return
|
||||
}
|
||||
132
vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go
generated
vendored
Normal file
132
vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package cloudwatch_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
"github.com/goamz/goamz/cloudwatch"
|
||||
"github.com/goamz/goamz/testutil"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
|
||||
type S struct {
|
||||
cw *cloudwatch.CloudWatch
|
||||
}
|
||||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
var testServer = testutil.NewHTTPServer()
|
||||
|
||||
func (s *S) SetUpSuite(c *C) {
|
||||
testServer.Start()
|
||||
auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
|
||||
s.cw, _ = cloudwatch.NewCloudWatch(auth, aws.ServiceInfo{testServer.URL, aws.V2Signature})
|
||||
}
|
||||
|
||||
func (s *S) TearDownTest(c *C) {
|
||||
testServer.Flush()
|
||||
}
|
||||
|
||||
func getTestAlarm() *cloudwatch.MetricAlarm {
|
||||
alarm := new(cloudwatch.MetricAlarm)
|
||||
|
||||
alarm.AlarmName = "TestAlarm"
|
||||
alarm.MetricName = "TestMetric"
|
||||
alarm.Namespace = "TestNamespace"
|
||||
alarm.ComparisonOperator = "LessThanThreshold"
|
||||
alarm.Threshold = 1
|
||||
alarm.EvaluationPeriods = 5
|
||||
alarm.Period = 60
|
||||
alarm.Statistic = "Sum"
|
||||
|
||||
return alarm
|
||||
}
|
||||
|
||||
func (s *S) TestPutAlarm(c *C) {
|
||||
testServer.Response(200, nil, "<RequestId>123</RequestId>")
|
||||
|
||||
alarm := getTestAlarm()
|
||||
|
||||
_, err := s.cw.PutMetricAlarm(alarm)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
req := testServer.WaitRequest()
|
||||
c.Assert(req.Method, Equals, "POST")
|
||||
c.Assert(req.URL.Path, Equals, "/")
|
||||
c.Assert(req.Form["Action"], DeepEquals, []string{"PutMetricAlarm"})
|
||||
c.Assert(req.Form["AlarmName"], DeepEquals, []string{"TestAlarm"})
|
||||
c.Assert(req.Form["ComparisonOperator"], DeepEquals, []string{"LessThanThreshold"})
|
||||
c.Assert(req.Form["EvaluationPeriods"], DeepEquals, []string{"5"})
|
||||
c.Assert(req.Form["Threshold"], DeepEquals, []string{"1.0000000000E+00"})
|
||||
c.Assert(req.Form["Period"], DeepEquals, []string{"60"})
|
||||
c.Assert(req.Form["Statistic"], DeepEquals, []string{"Sum"})
|
||||
}
|
||||
|
||||
func (s *S) TestPutAlarmWithAction(c *C) {
|
||||
testServer.Response(200, nil, "<RequestId>123</RequestId>")
|
||||
|
||||
alarm := getTestAlarm()
|
||||
|
||||
alarm.AlarmActions = []cloudwatch.AlarmAction{
|
||||
cloudwatch.AlarmAction{
|
||||
ARN: "123",
|
||||
},
|
||||
}
|
||||
|
||||
alarm.OkActions = []cloudwatch.AlarmAction{
|
||||
cloudwatch.AlarmAction{
|
||||
ARN: "456",
|
||||
},
|
||||
}
|
||||
|
||||
alarm.InsufficientDataActions = []cloudwatch.AlarmAction{
|
||||
cloudwatch.AlarmAction{
|
||||
ARN: "789",
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.cw.PutMetricAlarm(alarm)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
req := testServer.WaitRequest()
|
||||
c.Assert(req.Method, Equals, "POST")
|
||||
c.Assert(req.URL.Path, Equals, "/")
|
||||
c.Assert(req.Form["Action"], DeepEquals, []string{"PutMetricAlarm"})
|
||||
c.Assert(req.Form["AlarmActions.member.1"], DeepEquals, []string{"123"})
|
||||
c.Assert(req.Form["OKActions.member.1"], DeepEquals, []string{"456"})
|
||||
c.Assert(req.Form["InsufficientDataActions.member.1"], DeepEquals, []string{"789"})
|
||||
c.Assert(req.Form["AlarmName"], DeepEquals, []string{"TestAlarm"})
|
||||
c.Assert(req.Form["ComparisonOperator"], DeepEquals, []string{"LessThanThreshold"})
|
||||
c.Assert(req.Form["EvaluationPeriods"], DeepEquals, []string{"5"})
|
||||
c.Assert(req.Form["Threshold"], DeepEquals, []string{"1.0000000000E+00"})
|
||||
c.Assert(req.Form["Period"], DeepEquals, []string{"60"})
|
||||
c.Assert(req.Form["Statistic"], DeepEquals, []string{"Sum"})
|
||||
}
|
||||
|
||||
func (s *S) TestPutAlarmInvalidComapirsonOperator(c *C) {
|
||||
testServer.Response(200, nil, "<RequestId>123</RequestId>")
|
||||
|
||||
alarm := getTestAlarm()
|
||||
|
||||
alarm.ComparisonOperator = "LessThan"
|
||||
|
||||
_, err := s.cw.PutMetricAlarm(alarm)
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(err.Error(), Equals, "ComparisonOperator is not valid")
|
||||
}
|
||||
|
||||
func (s *S) TestPutAlarmInvalidStatistic(c *C) {
|
||||
testServer.Response(200, nil, "<RequestId>123</RequestId>")
|
||||
|
||||
alarm := getTestAlarm()
|
||||
|
||||
alarm.Statistic = "Count"
|
||||
|
||||
_, err := s.cw.PutMetricAlarm(alarm)
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(err.Error(), Equals, "Invalid statistic value supplied")
|
||||
}
|
||||
1
vendor/github.com/goamz/goamz/dynamodb/.gitignore
generated
vendored
Normal file
1
vendor/github.com/goamz/goamz/dynamodb/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
dynamodb_local*
|
||||
13
vendor/github.com/goamz/goamz/dynamodb/Makefile
generated
vendored
Normal file
13
vendor/github.com/goamz/goamz/dynamodb/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
DYNAMODB_LOCAL_VERSION = 2013-12-12
|
||||
|
||||
launch: DynamoDBLocal.jar
|
||||
cd dynamodb_local_$(DYNAMODB_LOCAL_VERSION) && java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar
|
||||
|
||||
DynamoDBLocal.jar: dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
|
||||
[ -d dynamodb_local_$(DYNAMODB_LOCAL_VERSION) ] || tar -zxf dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
|
||||
|
||||
dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz:
|
||||
curl -O https://s3-us-west-2.amazonaws.com/dynamodb-local/dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
|
||||
|
||||
clean:
|
||||
rm -rf dynamodb_local_$(DYNAMODB_LOCAL_VERSION)*
|
||||
27
vendor/github.com/goamz/goamz/dynamodb/README.md
generated
vendored
Normal file
27
vendor/github.com/goamz/goamz/dynamodb/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Running integration tests
|
||||
|
||||
## against DynamoDB local
|
||||
|
||||
To download and launch DynamoDB local:
|
||||
|
||||
```sh
|
||||
$ make
|
||||
```
|
||||
|
||||
To test:
|
||||
|
||||
```sh
|
||||
$ go test -v -amazon
|
||||
```
|
||||
|
||||
## against real DynamoDB server on us-east
|
||||
|
||||
_WARNING_: Some dangerous operations such as `DeleteTable` will be performed during the tests. Please be careful.
|
||||
|
||||
To test:
|
||||
|
||||
```sh
|
||||
$ go test -v -amazon -local=false
|
||||
```
|
||||
|
||||
_Note_: Running tests against real DynamoDB will take several minutes.
|
||||
185
vendor/github.com/goamz/goamz/dynamodb/attribute.go
generated
vendored
Executable file
185
vendor/github.com/goamz/goamz/dynamodb/attribute.go
generated
vendored
Executable file
|
|
@ -0,0 +1,185 @@
|
|||
package dynamodb
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
TYPE_STRING = "S"
|
||||
TYPE_NUMBER = "N"
|
||||
TYPE_BINARY = "B"
|
||||
|
||||
TYPE_STRING_SET = "SS"
|
||||
TYPE_NUMBER_SET = "NS"
|
||||
TYPE_BINARY_SET = "BS"
|
||||
|
||||
COMPARISON_EQUAL = "EQ"
|
||||
COMPARISON_NOT_EQUAL = "NE"
|
||||
COMPARISON_LESS_THAN_OR_EQUAL = "LE"
|
||||
COMPARISON_LESS_THAN = "LT"
|
||||
COMPARISON_GREATER_THAN_OR_EQUAL = "GE"
|
||||
COMPARISON_GREATER_THAN = "GT"
|
||||
COMPARISON_ATTRIBUTE_EXISTS = "NOT_NULL"
|
||||
COMPARISON_ATTRIBUTE_DOES_NOT_EXIST = "NULL"
|
||||
COMPARISON_CONTAINS = "CONTAINS"
|
||||
COMPARISON_DOES_NOT_CONTAIN = "NOT_CONTAINS"
|
||||
COMPARISON_BEGINS_WITH = "BEGINS_WITH"
|
||||
COMPARISON_IN = "IN"
|
||||
COMPARISON_BETWEEN = "BETWEEN"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
HashKey string
|
||||
RangeKey string
|
||||
}
|
||||
|
||||
type PrimaryKey struct {
|
||||
KeyAttribute *Attribute
|
||||
RangeAttribute *Attribute
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
Type string
|
||||
Name string
|
||||
Value string
|
||||
SetValues []string
|
||||
Exists string // exists on dynamodb? Values: "true", "false", or ""
|
||||
}
|
||||
|
||||
type AttributeComparison struct {
|
||||
AttributeName string
|
||||
ComparisonOperator string
|
||||
AttributeValueList []Attribute // contains attributes with only types and names (value ignored)
|
||||
}
|
||||
|
||||
func NewEqualInt64AttributeComparison(attributeName string, equalToValue int64) *AttributeComparison {
|
||||
numeric := NewNumericAttribute(attributeName, strconv.FormatInt(equalToValue, 10))
|
||||
return &AttributeComparison{attributeName,
|
||||
COMPARISON_EQUAL,
|
||||
[]Attribute{*numeric},
|
||||
}
|
||||
}
|
||||
|
||||
func NewEqualStringAttributeComparison(attributeName string, equalToValue string) *AttributeComparison {
|
||||
str := NewStringAttribute(attributeName, equalToValue)
|
||||
return &AttributeComparison{attributeName,
|
||||
COMPARISON_EQUAL,
|
||||
[]Attribute{*str},
|
||||
}
|
||||
}
|
||||
|
||||
func NewStringAttributeComparison(attributeName string, comparisonOperator string, value string) *AttributeComparison {
|
||||
valueToCompare := NewStringAttribute(attributeName, value)
|
||||
return &AttributeComparison{attributeName,
|
||||
comparisonOperator,
|
||||
[]Attribute{*valueToCompare},
|
||||
}
|
||||
}
|
||||
|
||||
func NewNumericAttributeComparison(attributeName string, comparisonOperator string, value int64) *AttributeComparison {
|
||||
valueToCompare := NewNumericAttribute(attributeName, strconv.FormatInt(value, 10))
|
||||
return &AttributeComparison{attributeName,
|
||||
comparisonOperator,
|
||||
[]Attribute{*valueToCompare},
|
||||
}
|
||||
}
|
||||
|
||||
func NewBinaryAttributeComparison(attributeName string, comparisonOperator string, value bool) *AttributeComparison {
|
||||
valueToCompare := NewBinaryAttribute(attributeName, strconv.FormatBool(value))
|
||||
return &AttributeComparison{attributeName,
|
||||
comparisonOperator,
|
||||
[]Attribute{*valueToCompare},
|
||||
}
|
||||
}
|
||||
|
||||
func NewStringAttribute(name string, value string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_STRING,
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func NewNumericAttribute(name string, value string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_NUMBER,
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBinaryAttribute(name string, value string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_BINARY,
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func NewStringSetAttribute(name string, values []string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_STRING_SET,
|
||||
Name: name,
|
||||
SetValues: values,
|
||||
}
|
||||
}
|
||||
|
||||
func NewNumericSetAttribute(name string, values []string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_NUMBER_SET,
|
||||
Name: name,
|
||||
SetValues: values,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBinarySetAttribute(name string, values []string) *Attribute {
|
||||
return &Attribute{
|
||||
Type: TYPE_BINARY_SET,
|
||||
Name: name,
|
||||
SetValues: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Attribute) SetType() bool {
|
||||
switch a.Type {
|
||||
case TYPE_BINARY_SET, TYPE_NUMBER_SET, TYPE_STRING_SET:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *Attribute) SetExists(exists bool) *Attribute {
|
||||
if exists {
|
||||
a.Exists = "true"
|
||||
} else {
|
||||
a.Exists = "false"
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (k *PrimaryKey) HasRange() bool {
|
||||
return k.RangeAttribute != nil
|
||||
}
|
||||
|
||||
// Useful when you may have many goroutines using a primary key, so they don't fuxor up your values.
|
||||
func (k *PrimaryKey) Clone(h string, r string) []Attribute {
|
||||
pk := &Attribute{
|
||||
Type: k.KeyAttribute.Type,
|
||||
Name: k.KeyAttribute.Name,
|
||||
Value: h,
|
||||
}
|
||||
|
||||
result := []Attribute{*pk}
|
||||
|
||||
if k.HasRange() {
|
||||
rk := &Attribute{
|
||||
Type: k.RangeAttribute.Type,
|
||||
Name: k.RangeAttribute.Name,
|
||||
Value: r,
|
||||
}
|
||||
|
||||
result = append(result, *rk)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
11
vendor/github.com/goamz/goamz/dynamodb/const.go
generated
vendored
Normal file
11
vendor/github.com/goamz/goamz/dynamodb/const.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package dynamodb
|
||||
|
||||
type ReturnValues string
|
||||
|
||||
const (
|
||||
NONE ReturnValues = "NONE"
|
||||
ALL_OLD ReturnValues = "ALL_HOLD"
|
||||
UPDATED_OLD ReturnValues = "UPDATED_OLD"
|
||||
ALL_NEW ReturnValues = "ALL_NEW"
|
||||
UPDATED_NEW ReturnValues = "UPDATED_NEW"
|
||||
)
|
||||
142
vendor/github.com/goamz/goamz/dynamodb/dynamodb.go
generated
vendored
Executable file
142
vendor/github.com/goamz/goamz/dynamodb/dynamodb.go
generated
vendored
Executable file
|
|
@ -0,0 +1,142 @@
|
|||
package dynamodb
|
||||
|
||||
import simplejson "github.com/bitly/go-simplejson"
|
||||
import (
|
||||
"errors"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Auth aws.Auth
|
||||
Region aws.Region
|
||||
}
|
||||
|
||||
/*
|
||||
type Query struct {
|
||||
Query string
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func NewQuery(queryParts []string) *Query {
|
||||
return &Query{
|
||||
"{" + strings.Join(queryParts, ",") + "}",
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const (
|
||||
// DynamoDBAPIPrefix is the versioned prefix for DynamoDB API commands.
|
||||
DynamoDBAPIPrefix = "DynamoDB_20120810."
|
||||
// DynamoDBStreamsAPIPrefix is the versioned prefix for DynamoDB Streams API commands.
|
||||
DynamoDBStreamsAPIPrefix = "DynamoDBStreams_20120810."
|
||||
)
|
||||
|
||||
// Specific error constants
|
||||
var ErrNotFound = errors.New("Item not found")
|
||||
|
||||
// Error represents an error in an operation with Dynamodb (following goamz/s3)
|
||||
type Error struct {
|
||||
StatusCode int // HTTP status code (200, 403, ...)
|
||||
Status string
|
||||
Code string // Dynamodb error code ("MalformedQueryString", ...)
|
||||
Message string // The human-oriented error message
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.Code + ": " + e.Message
|
||||
}
|
||||
|
||||
func buildError(r *http.Response, jsonBody []byte) error {
|
||||
|
||||
ddbError := Error{
|
||||
StatusCode: r.StatusCode,
|
||||
Status: r.Status,
|
||||
}
|
||||
// TODO return error if Unmarshal fails?
|
||||
|
||||
json, err := simplejson.NewJson(jsonBody)
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse body as JSON")
|
||||
return err
|
||||
}
|
||||
ddbError.Message = json.Get("message").MustString()
|
||||
|
||||
// Of the form: com.amazon.coral.validate#ValidationException
|
||||
// We only want the last part
|
||||
codeStr := json.Get("__type").MustString()
|
||||
hashIndex := strings.Index(codeStr, "#")
|
||||
if hashIndex > 0 {
|
||||
codeStr = codeStr[hashIndex+1:]
|
||||
}
|
||||
ddbError.Code = codeStr
|
||||
|
||||
return &ddbError
|
||||
}
|
||||
|
||||
func (s *Server) queryServer(target string, query *Query) ([]byte, error) {
|
||||
data := strings.NewReader(query.String())
|
||||
var endpoint string
|
||||
if isStreamsTarget(target) {
|
||||
endpoint = s.Region.DynamoDBStreamsEndpoint
|
||||
} else {
|
||||
endpoint = s.Region.DynamoDBEndpoint
|
||||
}
|
||||
hreq, err := http.NewRequest("POST", endpoint+"/", data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hreq.Header.Set("Content-Type", "application/x-amz-json-1.0")
|
||||
hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat))
|
||||
hreq.Header.Set("X-Amz-Target", target)
|
||||
|
||||
token := s.Auth.Token()
|
||||
if token != "" {
|
||||
hreq.Header.Set("X-Amz-Security-Token", token)
|
||||
}
|
||||
|
||||
signer := aws.NewV4Signer(s.Auth, "dynamodb", s.Region)
|
||||
signer.Sign(hreq)
|
||||
|
||||
resp, err := http.DefaultClient.Do(hreq)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error calling Amazon")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Could not read response body")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html
|
||||
// "A response code of 200 indicates the operation was successful."
|
||||
if resp.StatusCode != 200 {
|
||||
ddbErr := buildError(resp, body)
|
||||
return nil, ddbErr
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func target(name string) string {
|
||||
return DynamoDBAPIPrefix + name
|
||||
}
|
||||
|
||||
func streamsTarget(name string) string {
|
||||
return DynamoDBStreamsAPIPrefix + name
|
||||
}
|
||||
|
||||
func isStreamsTarget(target string) bool {
|
||||
return strings.HasPrefix(target, DynamoDBStreamsAPIPrefix)
|
||||
}
|
||||
166
vendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go
generated
vendored
Executable file
166
vendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go
generated
vendored
Executable file
|
|
@ -0,0 +1,166 @@
|
|||
package dynamodb_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goamz/goamz/aws"
|
||||
"github.com/goamz/goamz/dynamodb"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
const TIMEOUT = 3 * time.Minute
|
||||
|
||||
var amazon = flag.Bool("amazon", false, "Enable tests against dynamodb")
|
||||
var local = flag.Bool("local", true, "Use DynamoDB local on 8080 instead of real server on us-east.")
|
||||
|
||||
var dynamodb_region aws.Region
|
||||
var dynamodb_auth aws.Auth
|
||||
|
||||
type DynamoDBTest struct {
|
||||
server *dynamodb.Server
|
||||
aws.Region // Exports Region
|
||||
TableDescriptionT dynamodb.TableDescriptionT
|
||||
table *dynamodb.Table
|
||||
}
|
||||
|
||||
// Delete all items in the table
|
||||
func (s *DynamoDBTest) TearDownTest(c *C) {
|
||||
pk, err := s.TableDescriptionT.BuildPrimaryKey()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
attrs, err := s.table.Scan(nil)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
for _, a := range attrs {
|
||||
key := &dynamodb.Key{
|
||||
HashKey: a[pk.KeyAttribute.Name].Value,
|
||||
}
|
||||
if pk.HasRange() {
|
||||
key.RangeKey = a[pk.RangeAttribute.Name].Value
|
||||
}
|
||||
if ok, err := s.table.DeleteItem(key); !ok {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DynamoDBTest) TearDownSuite(c *C) {
|
||||
// return immediately in the case of calling c.Skip() in SetUpSuite()
|
||||
if s.server == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// check whether the table exists
|
||||
if tables, err := s.server.ListTables(); err != nil {
|
||||
c.Fatal(err)
|
||||
} else {
|
||||
if !findTableByName(tables, s.TableDescriptionT.TableName) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the table and wait
|
||||
if _, err := s.server.DeleteTable(s.TableDescriptionT); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
timeout := time.After(TIMEOUT)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
tables, err := s.server.ListTables()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
if findTableByName(tables, s.TableDescriptionT.TableName) {
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
done <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-timeout:
|
||||
c.Error("Expect the table to be deleted but timed out")
|
||||
close(done)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DynamoDBTest) WaitUntilStatus(c *C, status string) {
|
||||
// We should wait until the table is in specified status because a real DynamoDB has some delay for ready
|
||||
done := make(chan bool)
|
||||
timeout := time.After(TIMEOUT)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
desc, err := s.table.DescribeTable()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
if desc.TableStatus == status {
|
||||
done <- true
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-timeout:
|
||||
c.Errorf("Expect a status to be %s, but timed out", status)
|
||||
close(done)
|
||||
}
|
||||
}
|
||||
|
||||
func setUpAuth(c *C) {
|
||||
if !*amazon {
|
||||
c.Skip("Test against amazon not enabled.")
|
||||
}
|
||||
if *local {
|
||||
c.Log("Using local server")
|
||||
dynamodb_region = aws.Region{
|
||||
DynamoDBEndpoint: "http://127.0.0.1:8000",
|
||||
DynamoDBStreamsEndpoint: "http://127.0.0.1:8000",
|
||||
}
|
||||
dynamodb_auth = aws.Auth{AccessKey: "DUMMY_KEY", SecretKey: "DUMMY_SECRET"}
|
||||
} else {
|
||||
c.Log("Using REAL AMAZON SERVER")
|
||||
dynamodb_region = aws.USEast
|
||||
auth, err := aws.EnvAuth()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
dynamodb_auth = auth
|
||||
}
|
||||
}
|
||||
|
||||
func findTableByName(tables []string, name string) bool {
|
||||
for _, t := range tables {
|
||||
if t == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue