dep 0.5 prune
This commit is contained in:
parent
94023fd9c3
commit
8fbbc0d7c1
527 changed files with 228 additions and 157973 deletions
219
Gopkg.lock
generated
219
Gopkg.lock
generated
|
|
@ -2,166 +2,357 @@
|
|||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b62a3c5b37db602bf1158e921da1a762315a4c37855fd418a14498aa87a342d5"
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["civil"]
|
||||
pruneopts = "NUT"
|
||||
revision = "0ebda48a7f143b1cce9eb37a8c1106ac762a3430"
|
||||
version = "v0.34.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f323f98930459f65f4699b5bfba563743680e2633d96e72d61a9732648e2d07c"
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:551eb5689acc063e875cd17d8c667cce5eb298f5c1562273cb886f2f8f81121e"
|
||||
name = "github.com/Azure/azure-sdk-for-go"
|
||||
packages = ["services/graphrbac/1.6/graphrbac","version"]
|
||||
packages = [
|
||||
"services/graphrbac/1.6/graphrbac",
|
||||
"version",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "1951233eb944a49aa5f7278cba8e3e32a8c958af"
|
||||
version = "v24.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9b74a0138f67968c3b48282efd29ad08bed3e380cac7589f85418638ed51e8d9"
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = ["autorest","autorest/adal","autorest/azure","autorest/date","autorest/to","autorest/validation","logger","tracing"]
|
||||
packages = [
|
||||
"autorest",
|
||||
"autorest/adal",
|
||||
"autorest/azure",
|
||||
"autorest/date",
|
||||
"autorest/to",
|
||||
"autorest/validation",
|
||||
"logger",
|
||||
"tracing",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "be17756531f50014397912b7aa557ec335e39b98"
|
||||
version = "v11.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:65b0d980b428a6ad4425f2df4cd5410edd81f044cf527bd1c345368444649e58"
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = ["gen-go/agent/common/v1","gen-go/agent/trace/v1","gen-go/resource/v1","gen-go/trace/v1"]
|
||||
packages = [
|
||||
"gen-go/agent/common/v1",
|
||||
"gen-go/agent/trace/v1",
|
||||
"gen-go/resource/v1",
|
||||
"gen-go/trace/v1",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "7f2434bc10da710debe5c4315ed6d4df454b4024"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:3a0e8b1ac13f6daa8e6e18b0129a8f1498ade5530fb55cba67c7312ddbb1c78c"
|
||||
name = "github.com/denisenkom/go-mssqldb"
|
||||
packages = [".","internal/cp"]
|
||||
packages = [
|
||||
".",
|
||||
"internal/cp",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "2fea367d496dade570d9c1959be58a98a9061522"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7a6852b35eb5bbc184561443762d225116ae630c26a7c4d90546619f1e7d2ad2"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:13e9a236e56e18fecb73f5b2f2eb7f60060a1a9bc27e5a7328ab22e275ecb63e"
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:745fa6a19eb7613f207a17b42db0c4425d553fd38ee9387bc686a4b87beb178b"
|
||||
name = "github.com/gokyle/sshkey"
|
||||
packages = [".","readpass"]
|
||||
packages = [
|
||||
".",
|
||||
"readpass",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "d32a9ef172a1ec91efdf3ce26b240c946285bfe7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:479e958ad7ae540d7a3c565d1839cc7c8ab9b627640144443f1e88d11d4023d0"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto","ptypes","ptypes/any","ptypes/duration","ptypes/timestamp","ptypes/wrappers"]
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "hack_global_ref"
|
||||
digest = "1:a45cc1a5e646cce0742dd386ed88240e0152f7b7fee7ed1cdf9a2356a739c580"
|
||||
name = "github.com/jessevdk/go-flags"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "3e2b0d3b82050426db6ebde363a66b2c7711d8fc"
|
||||
source = "https://github.com/tg123/go-flags"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7f6c7654b72f950f1774b593357ce70314dd0116e3a1ed0e9a02513a73506208"
|
||||
name = "github.com/jinzhu/gorm"
|
||||
packages = [".","dialects/mssql","dialects/mysql","dialects/postgres","dialects/sqlite"]
|
||||
packages = [
|
||||
".",
|
||||
"dialects/mssql",
|
||||
"dialects/mysql",
|
||||
"dialects/postgres",
|
||||
"dialects/sqlite",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "472c70caa40267cb89fd8facb07fe6454b578626"
|
||||
version = "v1.9.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:802f75230c29108e787d40679f9bf5da1a5673eaf5c10eb89afd993e18972909"
|
||||
name = "github.com/jinzhu/inflection"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "04140366298a54a039076d798123ffa108fff46c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:981b5a5a9c05b9f5645e68e2c13dd498a048e8ab0aec07397f33edb3301f2569"
|
||||
name = "github.com/lib/pq"
|
||||
packages = [".","hstore","oid"]
|
||||
packages = [
|
||||
".",
|
||||
"hstore",
|
||||
"oid",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c9724c929d27a14475a45b17a267dbc60671c0bc2c5c05ed21f011f7b5bc9fb5"
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:15bc31ae39f989dda613930c1de860aced7b922502f8d9d861998fc195b7937c"
|
||||
name = "github.com/msteinert/pam"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "f4cd9f5e29232537a12db1678f48c702ad6896b7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f2805adeca595d7dbd25173b57f83daaa79f44d43475263c4e34b05020eac9a7"
|
||||
name = "go.opencensus.io"
|
||||
packages = [".","exemplar","internal","internal/tagencoding","plugin/ochttp","plugin/ochttp/propagation/b3","plugin/ochttp/propagation/tracecontext","stats","stats/internal","stats/view","tag","trace","trace/internal","trace/propagation","trace/tracestate"]
|
||||
packages = [
|
||||
".",
|
||||
"exemplar",
|
||||
"internal",
|
||||
"internal/tagencoding",
|
||||
"plugin/ochttp",
|
||||
"plugin/ochttp/propagation/b3",
|
||||
"plugin/ochttp/propagation/tracecontext",
|
||||
"stats",
|
||||
"stats/internal",
|
||||
"stats/view",
|
||||
"tag",
|
||||
"trace",
|
||||
"trace/internal",
|
||||
"trace/propagation",
|
||||
"trace/tracestate",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2d30be27dd2b729c66b70701d20cbae931800b707a5efb8e85546b0314a413a2"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","internal/subtle","md4","poly1305","ssh","ssh/knownhosts","ssh/testdata"]
|
||||
packages = [
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"internal/chacha20",
|
||||
"internal/subtle",
|
||||
"md4",
|
||||
"poly1305",
|
||||
"ssh",
|
||||
"ssh/knownhosts",
|
||||
"ssh/testdata",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "0a9e5a7b288dccb74e2efd0fe62005aaf2a6ddbb"
|
||||
source = "https://github.com/tg123/sshpiper.crypto"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e947d55d941f561ff2ecd75221e9befa27dffbdaa4507925e57c1e452ff9f096"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","http/httpguts","http2","http2/hpack","idna","internal/timeseries","trace"]
|
||||
packages = [
|
||||
"context",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "1e06a53dbb7e2ed46e91183f219db23c6943c532"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
pruneopts = "NUT"
|
||||
revision = "37e7f081c4d4c64e13b10787722085407fe5d15f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d3d29753d439e2dd58bab6ed54426db663ffa4673e522971ec14f430d08c6e85"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = "NUT"
|
||||
revision = "7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e7071ed636b5422cc51c0e3a6cebc229d6c9fffc528814b519a980641422d619"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643"
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
pruneopts = "NUT"
|
||||
revision = "19e022d8cf43ce81f046bae8cc18c5397cc7732f"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
|
||||
name = "google.golang.org/appengine"
|
||||
packages = ["cloudsql"]
|
||||
pruneopts = "NUT"
|
||||
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "NUT"
|
||||
revision = "ae2f86662275e140f395167f1dab7081a5bd5fa8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:638e6e596d67d0a0c8aeb76ebdcf73561b701ea43f21963b1db231d96ed7db68"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [".","balancer","balancer/base","balancer/roundrobin","binarylog/grpc_binarylog_v1","codes","connectivity","credentials","credentials/internal","encoding","encoding/proto","grpclog","internal","internal/backoff","internal/binarylog","internal/channelz","internal/envconfig","internal/grpcrand","internal/grpcsync","internal/syscall","internal/transport","keepalive","metadata","naming","peer","resolver","resolver/dns","resolver/passthrough","stats","status","tap"]
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"binarylog/grpc_binarylog_v1",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"credentials/internal",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/binarylog",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/grpcsync",
|
||||
"internal/syscall",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8"
|
||||
version = "v1.17.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "462e8a5c0f53ae4a78ab2d005630854f64df61142ef3409475ff2b3f1c5640fb"
|
||||
input-imports = [
|
||||
"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac",
|
||||
"github.com/Azure/go-autorest/autorest",
|
||||
"github.com/Azure/go-autorest/autorest/adal",
|
||||
"github.com/Azure/go-autorest/autorest/azure",
|
||||
"github.com/go-sql-driver/mysql",
|
||||
"github.com/gokyle/sshkey",
|
||||
"github.com/jessevdk/go-flags",
|
||||
"github.com/jinzhu/gorm",
|
||||
"github.com/jinzhu/gorm/dialects/mssql",
|
||||
"github.com/jinzhu/gorm/dialects/mysql",
|
||||
"github.com/jinzhu/gorm/dialects/postgres",
|
||||
"github.com/jinzhu/gorm/dialects/sqlite",
|
||||
"github.com/msteinert/pam",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/crypto/ssh/knownhosts",
|
||||
"golang.org/x/crypto/ssh/testdata",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@
|
|||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
non-go = true
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
|
|
|||
1024
vendor/cloud.google.com/go/CHANGES.md
generated
vendored
1024
vendor/cloud.google.com/go/CHANGES.md
generated
vendored
File diff suppressed because it is too large
Load diff
44
vendor/cloud.google.com/go/CODE_OF_CONDUCT.md
generated
vendored
44
vendor/cloud.google.com/go/CODE_OF_CONDUCT.md
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project,
|
||||
and in the interest of fostering an open and welcoming community,
|
||||
we pledge to respect all people who contribute through reporting issues,
|
||||
posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project
|
||||
a harassment-free experience for everyone,
|
||||
regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance,
|
||||
body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information,
|
||||
such as physical or electronic
|
||||
addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct.
|
||||
By adopting this Code of Conduct,
|
||||
project maintainers commit themselves to fairly and consistently
|
||||
applying these principles to every aspect of managing this project.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by opening an issue
|
||||
or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
|
||||
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
||||
|
||||
234
vendor/cloud.google.com/go/CONTRIBUTING.md
generated
vendored
234
vendor/cloud.google.com/go/CONTRIBUTING.md
generated
vendored
|
|
@ -1,234 +0,0 @@
|
|||
# Contributing
|
||||
|
||||
1. Sign one of the contributor license agreements below.
|
||||
1. `go get golang.org/x/review/git-codereview` to install the code reviewing
|
||||
tool.
|
||||
1. You will need to ensure that your `GOBIN` directory (by default
|
||||
`$GOPATH/bin`) is in your `PATH` so that git can find the command.
|
||||
1. If you would like, you may want to set up aliases for git-codereview,
|
||||
such that `git codereview change` becomes `git change`. See the
|
||||
[godoc](https://godoc.org/golang.org/x/review/git-codereview) for details.
|
||||
1. Should you run into issues with the git-codereview tool, please note
|
||||
that all error messages will assume that you have set up these aliases.
|
||||
1. Get the cloud package by running `go get -d cloud.google.com/go`.
|
||||
1. If you have already checked out the source, make sure that the remote
|
||||
git origin is https://code.googlesource.com/gocloud:
|
||||
|
||||
```
|
||||
git remote set-url origin https://code.googlesource.com/gocloud
|
||||
```
|
||||
|
||||
1. Make sure your auth is configured correctly by visiting
|
||||
https://code.googlesource.com, clicking "Generate Password", and following the
|
||||
directions.
|
||||
1. Make changes and create a change by running `git codereview change <name>`,
|
||||
provide a commit message, and use `git codereview mail` to create a Gerrit CL.
|
||||
1. Keep amending to the change with `git codereview change` and mail as your
|
||||
receive feedback. Each new mailed amendment will create a new patch set for
|
||||
your change in Gerrit.
|
||||
|
||||
## Integration Tests
|
||||
|
||||
In addition to the unit tests, you may run the integration test suite. These
|
||||
directions describe setting up your environment to run integration tests for
|
||||
_all_ packages: note that many of these instructions may be redundant if you
|
||||
intend only to run integration tests on a single package.
|
||||
|
||||
#### GCP Setup
|
||||
|
||||
To run the integrations tests, creation and configuration of two projects in
|
||||
the Google Developers Console is required: one specifically for Firestore
|
||||
integration tests, and another for all other integration tests. We'll refer to
|
||||
these projects as "general project" and "Firestore project".
|
||||
|
||||
After creating each project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount)
|
||||
for each project. Ensure the project-level **Owner**
|
||||
[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to
|
||||
each service account. During the creation of the service account, you should
|
||||
download the JSON credential file for use later.
|
||||
|
||||
Next, ensure the following APIs are enabled in the general project:
|
||||
|
||||
- BigQuery API
|
||||
- BigQuery Data Transfer API
|
||||
- Cloud Dataproc API
|
||||
- Cloud Dataproc Control API Private
|
||||
- Cloud Datastore API
|
||||
- Cloud Firestore API
|
||||
- Cloud Key Management Service (KMS) API
|
||||
- Cloud Natural Language API
|
||||
- Cloud OS Login API
|
||||
- Cloud Pub/Sub API
|
||||
- Cloud Resource Manager API
|
||||
- Cloud Spanner API
|
||||
- Cloud Speech API
|
||||
- Cloud Translation API
|
||||
- Cloud Video Intelligence API
|
||||
- Cloud Vision API
|
||||
- Compute Engine API
|
||||
- Compute Engine Instance Group Manager API
|
||||
- Container Registry API
|
||||
- Firebase Rules API
|
||||
- Google Cloud APIs
|
||||
- Google Cloud Deployment Manager V2 API
|
||||
- Google Cloud SQL
|
||||
- Google Cloud Storage
|
||||
- Google Cloud Storage JSON API
|
||||
- Google Compute Engine Instance Group Updater API
|
||||
- Google Compute Engine Instance Groups API
|
||||
- Kubernetes Engine API
|
||||
- Stackdriver Error Reporting API
|
||||
|
||||
Next, create a Datastore database in the general project, and a Firestore
|
||||
database in the Firestore project.
|
||||
|
||||
Finally, in the general project, create an API key for the translate API:
|
||||
|
||||
- Go to GCP Developer Console.
|
||||
- Navigate to APIs & Services > Credentials.
|
||||
- Click Create Credentials > API Key.
|
||||
- Save this key for use in `GCLOUD_TESTS_API_KEY` as described below.
|
||||
|
||||
#### Local Setup
|
||||
|
||||
Once the two projects are created and configured, set the following environment
|
||||
variables:
|
||||
|
||||
- `GCLOUD_TESTS_GOLANG_PROJECT_ID`: Developers Console project's ID (e.g.
|
||||
bamboo-shift-455) for the general project.
|
||||
- `GCLOUD_TESTS_GOLANG_KEY`: The path to the JSON key file of the general
|
||||
project's service account.
|
||||
- `GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID`: Developers Console project's ID
|
||||
(e.g. doorway-cliff-677) for the Firestore project.
|
||||
- `GCLOUD_TESTS_GOLANG_FIRESTORE_KEY`: The path to the JSON key file of the
|
||||
Firestore project's service account.
|
||||
- `GCLOUD_TESTS_GOLANG_KEYRING`: The full name of the keyring for the tests,
|
||||
in the form
|
||||
"projects/P/locations/L/keyRings/R". The creation of this is described below.
|
||||
- `GCLOUD_TESTS_API_KEY`: API key for using the Translate API.
|
||||
- `GCLOUD_TESTS_GOLANG_ZONE`: Compute Engine zone.
|
||||
|
||||
Install the [gcloud command-line tool][gcloudcli] to your machine and use it to
|
||||
create some resources used in integration tests.
|
||||
|
||||
From the project's root directory:
|
||||
|
||||
``` sh
|
||||
# Sets the default project in your env.
|
||||
$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID
|
||||
|
||||
# Authenticates the gcloud tool with your account.
|
||||
$ gcloud auth login
|
||||
|
||||
# Create the indexes used in the datastore integration tests.
|
||||
$ gcloud datastore create-indexes datastore/testdata/index.yaml
|
||||
|
||||
# Creates a Google Cloud storage bucket with the same name as your test project,
|
||||
# and with the Stackdriver Logging service account as owner, for the sink
|
||||
# integration tests in logging.
|
||||
$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID
|
||||
$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID
|
||||
|
||||
# Creates a PubSub topic for integration tests of storage notifications.
|
||||
$ gcloud beta pubsub topics create go-storage-notification-test
|
||||
# Next, go to the Pub/Sub dashboard in GCP console. Authorize the user
|
||||
# "service-<numberic project id>@gs-project-accounts.iam.gserviceaccount.com"
|
||||
# as a publisher to that topic.
|
||||
|
||||
# Creates a Spanner instance for the spanner integration tests.
|
||||
$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 10 --description 'Instance for go client test'
|
||||
# NOTE: Spanner instances are priced by the node-hour, so you may want to
|
||||
# delete the instance after testing with 'gcloud beta spanner instances delete'.
|
||||
|
||||
$ export MY_KEYRING=some-keyring-name
|
||||
$ export MY_LOCATION=global
|
||||
# Creates a KMS keyring, in the same location as the default location for your
|
||||
# project's buckets.
|
||||
$ gcloud kms keyrings create $MY_KEYRING --location $MY_LOCATION
|
||||
# Creates two keys in the keyring, named key1 and key2.
|
||||
$ gcloud kms keys create key1 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption
|
||||
$ gcloud kms keys create key2 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption
|
||||
# Sets the GCLOUD_TESTS_GOLANG_KEYRING environment variable.
|
||||
$ export GCLOUD_TESTS_GOLANG_KEYRING=projects/$GCLOUD_TESTS_GOLANG_PROJECT_ID/locations/$MY_LOCATION/keyRings/$MY_KEYRING
|
||||
# Authorizes Google Cloud Storage to encrypt and decrypt using key1.
|
||||
gsutil kms authorize -p $GCLOUD_TESTS_GOLANG_PROJECT_ID -k $GCLOUD_TESTS_GOLANG_KEYRING/cryptoKeys/key1
|
||||
```
|
||||
|
||||
#### Running
|
||||
|
||||
Once you've done the necessary setup, you can run the integration tests by
|
||||
running:
|
||||
|
||||
``` sh
|
||||
$ go test -v cloud.google.com/go/...
|
||||
```
|
||||
|
||||
#### Replay
|
||||
|
||||
Some packages can record the RPCs during integration tests to a file for
|
||||
subsequent replay. To record, pass the `-record` flag to `go test`. The
|
||||
recording will be saved to the _package_`.replay` file. To replay integration
|
||||
tests from a saved recording, the replay file must be present, the `-short`
|
||||
flag must be passed to `go test`, and the `GCLOUD_TESTS_GOLANG_ENABLE_REPLAY`
|
||||
environment variable must have a non-empty value.
|
||||
|
||||
## Contributor License Agreements
|
||||
|
||||
Before we can accept your pull requests you'll need to sign a Contributor
|
||||
License Agreement (CLA):
|
||||
|
||||
- **If you are an individual writing original source code** and **you own the
|
||||
intellectual property**, then you'll need to sign an [individual CLA][indvcla].
|
||||
- **If you work for a company that wants to allow you to contribute your
|
||||
work**, then you'll need to sign a [corporate CLA][corpcla].
|
||||
|
||||
You can sign these electronically (just scroll to the bottom). After that,
|
||||
we'll be able to accept your pull requests.
|
||||
|
||||
## Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project,
|
||||
and in the interest of fostering an open and welcoming community,
|
||||
we pledge to respect all people who contribute through reporting issues,
|
||||
posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project
|
||||
a harassment-free experience for everyone,
|
||||
regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance,
|
||||
body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information,
|
||||
such as physical or electronic
|
||||
addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct.
|
||||
By adopting this Code of Conduct,
|
||||
project maintainers commit themselves to fairly and consistently
|
||||
applying these principles to every aspect of managing this project.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by opening an issue
|
||||
or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
|
||||
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
||||
|
||||
[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/
|
||||
[indvcla]: https://developers.google.com/open-source/cla/individual
|
||||
[corpcla]: https://developers.google.com/open-source/cla/corporate
|
||||
505
vendor/cloud.google.com/go/README.md
generated
vendored
505
vendor/cloud.google.com/go/README.md
generated
vendored
|
|
@ -1,505 +0,0 @@
|
|||
# Google Cloud Client Libraries for Go
|
||||
|
||||
[](https://godoc.org/cloud.google.com/go)
|
||||
|
||||
Go packages for [Google Cloud Platform](https://cloud.google.com) services.
|
||||
|
||||
``` go
|
||||
import "cloud.google.com/go"
|
||||
```
|
||||
|
||||
To install the packages on your system, *do not clone the repo*. Instead use
|
||||
|
||||
```
|
||||
$ go get -u cloud.google.com/go/...
|
||||
```
|
||||
|
||||
**NOTE:** Some of these packages are under development, and may occasionally
|
||||
make backwards-incompatible changes.
|
||||
|
||||
**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud).
|
||||
|
||||
* [News](#news)
|
||||
* [Supported APIs](#supported-apis)
|
||||
* [Go Versions Supported](#go-versions-supported)
|
||||
* [Authorization](#authorization)
|
||||
* [Cloud Datastore](#cloud-datastore-)
|
||||
* [Cloud Storage](#cloud-storage-)
|
||||
* [Cloud Pub/Sub](#cloud-pub-sub-)
|
||||
* [BigQuery](#cloud-bigquery-)
|
||||
* [Stackdriver Logging](#stackdriver-logging-)
|
||||
* [Cloud Spanner](#cloud-spanner-)
|
||||
|
||||
|
||||
## News
|
||||
|
||||
_7 August 2018_
|
||||
|
||||
As of November 1, the code in the repo will no longer support Go versions 1.8
|
||||
and earlier. No one other than AppEngine users should be on those old versions,
|
||||
and AppEngine
|
||||
[Standard](https://groups.google.com/forum/#!topic/google-appengine-go/e7oPNomd7ak)
|
||||
and
|
||||
[Flex](https://groups.google.com/forum/#!topic/google-appengine-go/wHsYtxvEbXI)
|
||||
will stop supporting new deployments with those versions on that date.
|
||||
|
||||
|
||||
Changes have been moved to [CHANGES](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CHANGES.md).
|
||||
|
||||
|
||||
## Supported APIs
|
||||
|
||||
Google API | Status | Package
|
||||
---------------------------------------------|--------------|-----------------------------------------------------------
|
||||
[Asset][cloud-asset] | alpha | [`godoc.org/cloud.google.com/go/asset/v1beta`][cloud-asset-ref]
|
||||
[BigQuery][cloud-bigquery] | stable | [`godoc.org/cloud.google.com/go/bigquery`][cloud-bigquery-ref]
|
||||
[Bigtable][cloud-bigtable] | stable | [`godoc.org/cloud.google.com/go/bigtable`][cloud-bigtable-ref]
|
||||
[Cloudtasks][cloud-tasks] | beta | [`godoc.org/cloud.google.com/go/cloudtasks/apiv2beta3`][cloud-tasks-ref]
|
||||
[Container][cloud-container] | stable | [`godoc.org/cloud.google.com/go/container/apiv1`][cloud-container-ref]
|
||||
[ContainerAnalysis][cloud-containeranalysis] | beta | [`godoc.org/cloud.google.com/go/containeranalysis/apiv1beta1`][cloud-containeranalysis-ref]
|
||||
[Dataproc][cloud-dataproc] | stable | [`godoc.org/cloud.google.com/go/dataproc/apiv1`][cloud-dataproc-ref]
|
||||
[Datastore][cloud-datastore] | stable | [`godoc.org/cloud.google.com/go/datastore`][cloud-datastore-ref]
|
||||
[Debugger][cloud-debugger] | alpha | [`godoc.org/cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref]
|
||||
[Dialogflow][cloud-dialogflow] | alpha | [`godoc.org/cloud.google.com/go/dialogflow/apiv2`][cloud-dialogflow-ref]
|
||||
[Data Loss Prevention][cloud-dlp] | alpha | [`godoc.org/cloud.google.com/go/dlp/apiv2`][cloud-dlp-ref]
|
||||
[ErrorReporting][cloud-errors] | alpha | [`godoc.org/cloud.google.com/go/errorreporting`][cloud-errors-ref]
|
||||
[Firestore][cloud-firestore] | beta | [`godoc.org/cloud.google.com/go/firestore`][cloud-firestore-ref]
|
||||
[IAM][cloud-iam] | stable | [`godoc.org/cloud.google.com/go/iam`][cloud-iam-ref]
|
||||
[KMS][cloud-kms] | stable | [`godoc.org/cloud.google.com/go/kms`][cloud-kms-ref]
|
||||
[Natural Language][cloud-natural-language] | stable | [`godoc.org/cloud.google.com/go/language/apiv1`][cloud-natural-language-ref]
|
||||
[Logging][cloud-logging] | stable | [`godoc.org/cloud.google.com/go/logging`][cloud-logging-ref]
|
||||
[Monitoring][cloud-monitoring] | alpha | [`godoc.org/cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref]
|
||||
[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/compute/docs/oslogin/rest`][cloud-oslogin-ref]
|
||||
[Pub/Sub][cloud-pubsub] | stable | [`godoc.org/cloud.google.com/go/pubsub`][cloud-pubsub-ref]
|
||||
[Memorystore][cloud-memorystore] | stable | [`godoc.org/cloud.google.com/go/redis/apiv1beta1`][cloud-memorystore-ref]
|
||||
[Spanner][cloud-spanner] | stable | [`godoc.org/cloud.google.com/go/spanner`][cloud-spanner-ref]
|
||||
[Speech][cloud-speech] | stable | [`godoc.org/cloud.google.com/go/speech/apiv1`][cloud-speech-ref]
|
||||
[Storage][cloud-storage] | stable | [`godoc.org/cloud.google.com/go/storage`][cloud-storage-ref]
|
||||
[Text To Speech][cloud-texttospeech] | alpha | [`godoc.org/cloud.google.com/go/texttospeech/apiv1`][cloud-storage-ref]
|
||||
[Trace][cloud-trace] | alpha | [`godoc.org/cloud.google.com/go/trace/apiv2`][cloud-translation-ref]
|
||||
[Translation][cloud-translation] | stable | [`godoc.org/cloud.google.com/go/translate`][cloud-translation-ref]
|
||||
[Video Intelligence][cloud-video] | alpha | [`godoc.org/cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref]
|
||||
[Vision][cloud-vision] | stable | [`godoc.org/cloud.google.com/go/vision/apiv1`][cloud-vision-ref]
|
||||
|
||||
> **Alpha status**: the API is still being actively developed. As a
|
||||
> result, it might change in backward-incompatible ways and is not recommended
|
||||
> for production use.
|
||||
>
|
||||
> **Beta status**: the API is largely complete, but still has outstanding
|
||||
> features and bugs to be addressed. There may be minor backwards-incompatible
|
||||
> changes where necessary.
|
||||
>
|
||||
> **Stable status**: the API is mature and ready for production use. We will
|
||||
> continue addressing bugs and feature requests.
|
||||
|
||||
Documentation and examples are available at
|
||||
https://godoc.org/cloud.google.com/go
|
||||
|
||||
Visit or join the
|
||||
[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce)
|
||||
for updates on these packages.
|
||||
|
||||
## Go Versions Supported
|
||||
|
||||
We support the two most recent major versions of Go. If Google App Engine uses
|
||||
an older version, we support that as well.
|
||||
|
||||
## Authorization
|
||||
|
||||
By default, each API will use [Google Application Default Credentials][default-creds]
|
||||
for authorization credentials used in calling the API endpoints. This will allow your
|
||||
application to run in many environments without requiring explicit configuration.
|
||||
|
||||
[snip]:# (auth)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
```
|
||||
|
||||
To authorize using a
|
||||
[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys),
|
||||
pass
|
||||
[`option.WithCredentialsFile`](https://godoc.org/google.golang.org/api/option#WithCredentialsFile)
|
||||
to the `NewClient` function of the desired package. For example:
|
||||
|
||||
[snip]:# (auth-JSON)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx, option.WithCredentialsFile("path/to/keyfile.json"))
|
||||
```
|
||||
|
||||
You can exert more control over authorization by using the
|
||||
[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to
|
||||
create an `oauth2.TokenSource`. Then pass
|
||||
[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource)
|
||||
to the `NewClient` function:
|
||||
[snip]:# (auth-ts)
|
||||
```go
|
||||
tokenSource := ...
|
||||
client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
|
||||
```
|
||||
|
||||
## Cloud Datastore [](https://godoc.org/cloud.google.com/go/datastore)
|
||||
|
||||
- [About Cloud Datastore][cloud-datastore]
|
||||
- [Activating the API for your project][cloud-datastore-activation]
|
||||
- [API documentation][cloud-datastore-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore)
|
||||
- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `datastore.Client` to use throughout your application:
|
||||
|
||||
[snip]:# (datastore-1)
|
||||
```go
|
||||
client, err := datastore.NewClient(ctx, "my-project-id")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
Then use that client to interact with the API:
|
||||
|
||||
[snip]:# (datastore-2)
|
||||
```go
|
||||
type Post struct {
|
||||
Title string
|
||||
Body string `datastore:",noindex"`
|
||||
PublishedAt time.Time
|
||||
}
|
||||
keys := []*datastore.Key{
|
||||
datastore.NameKey("Post", "post1", nil),
|
||||
datastore.NameKey("Post", "post2", nil),
|
||||
}
|
||||
posts := []*Post{
|
||||
{Title: "Post 1", Body: "...", PublishedAt: time.Now()},
|
||||
{Title: "Post 2", Body: "...", PublishedAt: time.Now()},
|
||||
}
|
||||
if _, err := client.PutMulti(ctx, keys, posts); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud Storage [](https://godoc.org/cloud.google.com/go/storage)
|
||||
|
||||
- [About Cloud Storage][cloud-storage]
|
||||
- [API documentation][cloud-storage-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `storage.Client` to use throughout your application:
|
||||
|
||||
[snip]:# (storage-1)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
[snip]:# (storage-2)
|
||||
```go
|
||||
// Read the object1 from bucket.
|
||||
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rc.Close()
|
||||
body, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud Pub/Sub [](https://godoc.org/cloud.google.com/go/pubsub)
|
||||
|
||||
- [About Cloud Pubsub][cloud-pubsub]
|
||||
- [API documentation][cloud-pubsub-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub)
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `pubsub.Client` to use throughout your application:
|
||||
|
||||
[snip]:# (pubsub-1)
|
||||
```go
|
||||
client, err := pubsub.NewClient(ctx, "project-id")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
Then use the client to publish and subscribe:
|
||||
|
||||
[snip]:# (pubsub-2)
|
||||
```go
|
||||
// Publish "hello world" on topic1.
|
||||
topic := client.Topic("topic1")
|
||||
res := topic.Publish(ctx, &pubsub.Message{
|
||||
Data: []byte("hello world"),
|
||||
})
|
||||
// The publish happens asynchronously.
|
||||
// Later, you can get the result from res:
|
||||
...
|
||||
msgID, err := res.Get(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Use a callback to receive messages via subscription1.
|
||||
sub := client.Subscription("subscription1")
|
||||
err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) {
|
||||
fmt.Println(m.Data)
|
||||
m.Ack() // Acknowledge that we've consumed the message.
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
## BigQuery [](https://godoc.org/cloud.google.com/go/bigquery)
|
||||
|
||||
- [About BigQuery][cloud-bigquery]
|
||||
- [API documentation][cloud-bigquery-docs]
|
||||
- [Go client documentation][cloud-bigquery-ref]
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `bigquery.Client` to use throughout your application:
|
||||
[snip]:# (bq-1)
|
||||
```go
|
||||
c, err := bigquery.NewClient(ctx, "my-project-ID")
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
|
||||
Then use that client to interact with the API:
|
||||
[snip]:# (bq-2)
|
||||
```go
|
||||
// Construct a query.
|
||||
q := c.Query(`
|
||||
SELECT year, SUM(number)
|
||||
FROM [bigquery-public-data:usa_names.usa_1910_2013]
|
||||
WHERE name = "William"
|
||||
GROUP BY year
|
||||
ORDER BY year
|
||||
`)
|
||||
// Execute the query.
|
||||
it, err := q.Read(ctx)
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// Iterate through the results.
|
||||
for {
|
||||
var values []bigquery.Value
|
||||
err := it.Next(&values)
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
fmt.Println(values)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Stackdriver Logging [](https://godoc.org/cloud.google.com/go/logging)
|
||||
|
||||
- [About Stackdriver Logging][cloud-logging]
|
||||
- [API documentation][cloud-logging-docs]
|
||||
- [Go client documentation][cloud-logging-ref]
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `logging.Client` to use throughout your application:
|
||||
[snip]:# (logging-1)
|
||||
```go
|
||||
ctx := context.Background()
|
||||
client, err := logging.NewClient(ctx, "my-project")
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
|
||||
Usually, you'll want to add log entries to a buffer to be periodically flushed
|
||||
(automatically and asynchronously) to the Stackdriver Logging service.
|
||||
[snip]:# (logging-2)
|
||||
```go
|
||||
logger := client.Logger("my-log")
|
||||
logger.Log(logging.Entry{Payload: "something happened!"})
|
||||
```
|
||||
|
||||
Close your client before your program exits, to flush any buffered log entries.
|
||||
[snip]:# (logging-3)
|
||||
```go
|
||||
err = client.Close()
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud Spanner [](https://godoc.org/cloud.google.com/go/spanner)
|
||||
|
||||
- [About Cloud Spanner][cloud-spanner]
|
||||
- [API documentation][cloud-spanner-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `spanner.Client` to use throughout your application:
|
||||
|
||||
[snip]:# (spanner-1)
|
||||
```go
|
||||
client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
[snip]:# (spanner-2)
|
||||
```go
|
||||
// Simple Reads And Writes
|
||||
_, err = client.Apply(ctx, []*spanner.Mutation{
|
||||
spanner.Insert("Users",
|
||||
[]string{"name", "email"},
|
||||
[]interface{}{"alice", "a@example.com"})})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
row, err := client.Single().ReadRow(ctx, "Users",
|
||||
spanner.Key{"alice"}, []string{"email"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Please, see the
|
||||
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md)
|
||||
document for details. We're using Gerrit for our code reviews. Please don't open pull
|
||||
requests against this repo, new pull requests will be automatically closed.
|
||||
|
||||
Please note that this project is released with a Contributor Code of Conduct.
|
||||
By participating in this project you agree to abide by its terms.
|
||||
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct)
|
||||
for more information.
|
||||
|
||||
[cloud-datastore]: https://cloud.google.com/datastore/
|
||||
[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore
|
||||
[cloud-datastore-docs]: https://cloud.google.com/datastore/docs
|
||||
[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate
|
||||
|
||||
[cloud-firestore]: https://cloud.google.com/firestore/
|
||||
[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore
|
||||
[cloud-firestore-docs]: https://cloud.google.com/firestore/docs
|
||||
[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate
|
||||
|
||||
[cloud-pubsub]: https://cloud.google.com/pubsub/
|
||||
[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub
|
||||
[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs
|
||||
|
||||
[cloud-storage]: https://cloud.google.com/storage/
|
||||
[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage
|
||||
[cloud-storage-docs]: https://cloud.google.com/storage/docs
|
||||
[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets
|
||||
|
||||
[cloud-bigtable]: https://cloud.google.com/bigtable/
|
||||
[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable
|
||||
|
||||
[cloud-bigquery]: https://cloud.google.com/bigquery/
|
||||
[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs
|
||||
[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery
|
||||
|
||||
[cloud-logging]: https://cloud.google.com/logging/
|
||||
[cloud-logging-docs]: https://cloud.google.com/logging/docs
|
||||
[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging
|
||||
|
||||
[cloud-monitoring]: https://cloud.google.com/monitoring/
|
||||
[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3
|
||||
|
||||
[cloud-vision]: https://cloud.google.com/vision
|
||||
[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1
|
||||
|
||||
[cloud-language]: https://cloud.google.com/natural-language
|
||||
[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1
|
||||
|
||||
[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest
|
||||
[cloud-oslogin-ref]: https://cloud.google.com/compute/docs/oslogin/rest
|
||||
|
||||
[cloud-speech]: https://cloud.google.com/speech
|
||||
[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1
|
||||
|
||||
[cloud-spanner]: https://cloud.google.com/spanner/
|
||||
[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner
|
||||
[cloud-spanner-docs]: https://cloud.google.com/spanner/docs
|
||||
|
||||
[cloud-translation]: https://cloud.google.com/translation
|
||||
[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation
|
||||
|
||||
[cloud-video]: https://cloud.google.com/video-intelligence/
|
||||
[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1
|
||||
|
||||
[cloud-errors]: https://cloud.google.com/error-reporting/
|
||||
[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting
|
||||
|
||||
[cloud-container]: https://cloud.google.com/containers/
|
||||
[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1
|
||||
|
||||
[cloud-debugger]: https://cloud.google.com/debugger/
|
||||
[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2
|
||||
|
||||
[cloud-dlp]: https://cloud.google.com/dlp/
|
||||
[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1
|
||||
|
||||
[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials
|
||||
|
||||
[cloud-dataproc]: https://cloud.google.com/dataproc/
|
||||
[cloud-dataproc-docs]: https://cloud.google.com/dataproc/docs
|
||||
[cloud-dataproc-ref]: https://godoc.org/cloud.google.com/go/dataproc/apiv1
|
||||
|
||||
[cloud-iam]: https://cloud.google.com/iam/
|
||||
[cloud-iam-docs]: https://cloud.google.com/iam/docs
|
||||
[cloud-iam-ref]: https://godoc.org/cloud.google.com/go/iam
|
||||
|
||||
[cloud-kms]: https://cloud.google.com/kms/
|
||||
[cloud-kms-docs]: https://cloud.google.com/kms/docs
|
||||
[cloud-kms-ref]: https://godoc.org/cloud.google.com/go/kms/apiv1
|
||||
|
||||
[cloud-natural-language]: https://cloud.google.com/natural-language/
|
||||
[cloud-natural-language-docs]: https://cloud.google.com/natural-language/docs
|
||||
[cloud-natural-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1
|
||||
|
||||
[cloud-memorystore]: https://cloud.google.com/memorystore/
|
||||
[cloud-memorystore-docs]: https://cloud.google.com/memorystore/docs
|
||||
[cloud-memorystore-ref]: https://godoc.org/cloud.google.com/go/redis/apiv1beta1
|
||||
|
||||
[cloud-texttospeech]: https://cloud.google.com/texttospeech/
|
||||
[cloud-texttospeech-docs]: https://cloud.google.com/texttospeech/docs
|
||||
[cloud-texttospeech-ref]: https://godoc.org/cloud.google.com/go/texttospeech/apiv1
|
||||
|
||||
[cloud-trace]: https://cloud.google.com/trace/
|
||||
[cloud-trace-docs]: https://cloud.google.com/trace/docs
|
||||
[cloud-trace-ref]: https://godoc.org/cloud.google.com/go/trace/apiv1
|
||||
|
||||
[cloud-dialogflow]: https://cloud.google.com/dialogflow-enterprise/
|
||||
[cloud-dialogflow-docs]: https://cloud.google.com/dialogflow-enterprise/docs/
|
||||
[cloud-dialogflow-ref]: https://godoc.org/cloud.google.com/go/dialogflow/apiv2
|
||||
|
||||
[cloud-containeranalysis]: https://cloud.google.com/container-registry/docs/container-analysis
|
||||
[cloud-containeranalysis-docs]: https://cloud.google.com/container-analysis/api/reference/rest/
|
||||
[cloud-containeranalysis-ref]: https://godoc.org/cloud.google.com/go/devtools/containeranalysis/apiv1beta1
|
||||
|
||||
[cloud-asset]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory
|
||||
[cloud-asset-docs]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory
|
||||
[cloud-asset-ref]: https://godoc.org/cloud.google.com/go/asset/apiv1
|
||||
|
||||
[cloud-tasks]: https://cloud.google.com/tasks/
|
||||
[cloud-tasks-ref]: https://godoc.org/cloud.google.com/go/cloudtasks/apiv2beta3
|
||||
47
vendor/cloud.google.com/go/RELEASING.md
generated
vendored
47
vendor/cloud.google.com/go/RELEASING.md
generated
vendored
|
|
@ -1,47 +0,0 @@
|
|||
# How to Create a New Release
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Install [releasetool](https://github.com/googleapis/releasetool).
|
||||
|
||||
## Create a release
|
||||
|
||||
1. `cd` into the root directory, e.g., `~/go/src/cloud.google.com/go`
|
||||
1. Checkout the master branch and ensure a clean and up-to-date state.
|
||||
```
|
||||
git checkout master
|
||||
git pull --tags origin master
|
||||
```
|
||||
1. Run releasetool to generate a changelog from the last version. Note,
|
||||
releasetool will prompt if the new version is a major, minor, or patch
|
||||
version.
|
||||
```
|
||||
releasetool start --language go
|
||||
```
|
||||
1. Format the output to match CHANGES.md.
|
||||
1. Submit a CL with the changes in CHANGES.md. The commit message should look
|
||||
like this (where `v0.31.0` is instead the correct version number):
|
||||
```
|
||||
all: Release v0.31.0
|
||||
```
|
||||
1. Wait for approval from all reviewers and then submit the CL.
|
||||
1. Return to the master branch and pull the release commit.
|
||||
```
|
||||
git checkout master
|
||||
git pull origin master
|
||||
```
|
||||
1. Tag the current commit with the new version (e.g., `v0.31.0`)
|
||||
```
|
||||
releasetool tag --language go
|
||||
```
|
||||
1. Publish the tag to GoogleSource (i.e., origin):
|
||||
```
|
||||
git push origin $NEW_VERSION
|
||||
```
|
||||
1. Visit the [releases page][releases] on GitHub and click the "Draft a new
|
||||
release" button. For tag version, enter the tag published in the previous
|
||||
step. For the release title, use the version (e.g., `v0.31.0`). For the
|
||||
description, copy the changes added to CHANGES.md.
|
||||
|
||||
|
||||
[releases]: https://github.com/GoogleCloudPlatform/google-cloud-go/releases
|
||||
73
vendor/cloud.google.com/go/authexample_test.go
generated
vendored
73
vendor/cloud.google.com/go/authexample_test.go
generated
vendored
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// 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 cloud_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cloud.google.com/go/datastore"
|
||||
"cloud.google.com/go/pubsub"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
// Google Application Default Credentials is the recommended way to authorize
|
||||
// and authenticate clients.
|
||||
//
|
||||
// For information on how to create and obtain Application Default Credentials, see
|
||||
// https://developers.google.com/identity/protocols/application-default-credentials.
|
||||
func Example_applicationDefaultCredentials() {
|
||||
client, err := datastore.NewClient(context.Background(), "project-id")
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
_ = client // Use the client.
|
||||
}
|
||||
|
||||
// You can use a file with credentials to authenticate and authorize, such as a JSON
|
||||
// key file associated with a Google service account. Service Account keys can be
|
||||
// created and downloaded from
|
||||
// https://console.developers.google.com/permissions/serviceaccounts.
|
||||
//
|
||||
// This example uses the Datastore client, but the same steps apply to
|
||||
// the other client libraries underneath this package.
|
||||
func Example_credentialsFile() {
|
||||
client, err := datastore.NewClient(context.Background(),
|
||||
"project-id", option.WithCredentialsFile("/path/to/service-account-key.json"))
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
_ = client // Use the client.
|
||||
}
|
||||
|
||||
// In some cases (for instance, you don't want to store secrets on disk), you can
|
||||
// create credentials from in-memory JSON and use the WithCredentials option.
|
||||
//
|
||||
// The google package in this example is at golang.org/x/oauth2/google.
|
||||
//
|
||||
// This example uses the PubSub client, but the same steps apply to
|
||||
// the other client libraries underneath this package.
|
||||
func Example_credentialsFromJSON() {
|
||||
ctx := context.Background()
|
||||
creds, err := google.CredentialsFromJSON(ctx, []byte("JSON creds"), pubsub.ScopePubSub)
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
client, err := pubsub.NewClient(ctx, "project-id", option.WithCredentials(creds))
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
_ = client // Use the client.
|
||||
}
|
||||
442
vendor/cloud.google.com/go/civil/civil_test.go
generated
vendored
442
vendor/cloud.google.com/go/civil/civil_test.go
generated
vendored
|
|
@ -1,442 +0,0 @@
|
|||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// 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 civil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestDates(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
date Date
|
||||
loc *time.Location
|
||||
wantStr string
|
||||
wantTime time.Time
|
||||
}{
|
||||
{
|
||||
date: Date{2014, 7, 29},
|
||||
loc: time.Local,
|
||||
wantStr: "2014-07-29",
|
||||
wantTime: time.Date(2014, time.July, 29, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
date: DateOf(time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local)),
|
||||
loc: time.UTC,
|
||||
wantStr: "2014-08-20",
|
||||
wantTime: time.Date(2014, 8, 20, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
date: DateOf(time.Date(999, time.January, 26, 0, 0, 0, 0, time.Local)),
|
||||
loc: time.UTC,
|
||||
wantStr: "0999-01-26",
|
||||
wantTime: time.Date(999, 1, 26, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
} {
|
||||
if got := test.date.String(); got != test.wantStr {
|
||||
t.Errorf("%#v.String() = %q, want %q", test.date, got, test.wantStr)
|
||||
}
|
||||
if got := test.date.In(test.loc); !got.Equal(test.wantTime) {
|
||||
t.Errorf("%#v.In(%v) = %v, want %v", test.date, test.loc, got, test.wantTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateIsValid(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
date Date
|
||||
want bool
|
||||
}{
|
||||
{Date{2014, 7, 29}, true},
|
||||
{Date{2000, 2, 29}, true},
|
||||
{Date{10000, 12, 31}, true},
|
||||
{Date{1, 1, 1}, true},
|
||||
{Date{0, 1, 1}, true}, // year zero is OK
|
||||
{Date{-1, 1, 1}, true}, // negative year is OK
|
||||
{Date{1, 0, 1}, false},
|
||||
{Date{1, 1, 0}, false},
|
||||
{Date{2016, 1, 32}, false},
|
||||
{Date{2016, 13, 1}, false},
|
||||
{Date{1, -1, 1}, false},
|
||||
{Date{1, 1, -1}, false},
|
||||
} {
|
||||
got := test.date.IsValid()
|
||||
if got != test.want {
|
||||
t.Errorf("%#v: got %t, want %t", test.date, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDate(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
str string
|
||||
want Date // if empty, expect an error
|
||||
}{
|
||||
{"2016-01-02", Date{2016, 1, 2}},
|
||||
{"2016-12-31", Date{2016, 12, 31}},
|
||||
{"0003-02-04", Date{3, 2, 4}},
|
||||
{"999-01-26", Date{}},
|
||||
{"", Date{}},
|
||||
{"2016-01-02x", Date{}},
|
||||
} {
|
||||
got, err := ParseDate(test.str)
|
||||
if got != test.want {
|
||||
t.Errorf("ParseDate(%q) = %+v, want %+v", test.str, got, test.want)
|
||||
}
|
||||
if err != nil && test.want != (Date{}) {
|
||||
t.Errorf("Unexpected error %v from ParseDate(%q)", err, test.str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateArithmetic(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
desc string
|
||||
start Date
|
||||
end Date
|
||||
days int
|
||||
}{
|
||||
{
|
||||
desc: "zero days noop",
|
||||
start: Date{2014, 5, 9},
|
||||
end: Date{2014, 5, 9},
|
||||
days: 0,
|
||||
},
|
||||
{
|
||||
desc: "crossing a year boundary",
|
||||
start: Date{2014, 12, 31},
|
||||
end: Date{2015, 1, 1},
|
||||
days: 1,
|
||||
},
|
||||
{
|
||||
desc: "negative number of days",
|
||||
start: Date{2015, 1, 1},
|
||||
end: Date{2014, 12, 31},
|
||||
days: -1,
|
||||
},
|
||||
{
|
||||
desc: "full leap year",
|
||||
start: Date{2004, 1, 1},
|
||||
end: Date{2005, 1, 1},
|
||||
days: 366,
|
||||
},
|
||||
{
|
||||
desc: "full non-leap year",
|
||||
start: Date{2001, 1, 1},
|
||||
end: Date{2002, 1, 1},
|
||||
days: 365,
|
||||
},
|
||||
{
|
||||
desc: "crossing a leap second",
|
||||
start: Date{1972, 6, 30},
|
||||
end: Date{1972, 7, 1},
|
||||
days: 1,
|
||||
},
|
||||
{
|
||||
desc: "dates before the unix epoch",
|
||||
start: Date{101, 1, 1},
|
||||
end: Date{102, 1, 1},
|
||||
days: 365,
|
||||
},
|
||||
} {
|
||||
if got := test.start.AddDays(test.days); got != test.end {
|
||||
t.Errorf("[%s] %#v.AddDays(%v) = %#v, want %#v", test.desc, test.start, test.days, got, test.end)
|
||||
}
|
||||
if got := test.end.DaysSince(test.start); got != test.days {
|
||||
t.Errorf("[%s] %#v.Sub(%#v) = %v, want %v", test.desc, test.end, test.start, got, test.days)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateBefore(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
d1, d2 Date
|
||||
want bool
|
||||
}{
|
||||
{Date{2016, 12, 31}, Date{2017, 1, 1}, true},
|
||||
{Date{2016, 1, 1}, Date{2016, 1, 1}, false},
|
||||
{Date{2016, 12, 30}, Date{2016, 12, 31}, true},
|
||||
} {
|
||||
if got := test.d1.Before(test.d2); got != test.want {
|
||||
t.Errorf("%v.Before(%v): got %t, want %t", test.d1, test.d2, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateAfter(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
d1, d2 Date
|
||||
want bool
|
||||
}{
|
||||
{Date{2016, 12, 31}, Date{2017, 1, 1}, false},
|
||||
{Date{2016, 1, 1}, Date{2016, 1, 1}, false},
|
||||
{Date{2016, 12, 30}, Date{2016, 12, 31}, false},
|
||||
} {
|
||||
if got := test.d1.After(test.d2); got != test.want {
|
||||
t.Errorf("%v.After(%v): got %t, want %t", test.d1, test.d2, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeToString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
str string
|
||||
time Time
|
||||
roundTrip bool // ParseTime(str).String() == str?
|
||||
}{
|
||||
{"13:26:33", Time{13, 26, 33, 0}, true},
|
||||
{"01:02:03.000023456", Time{1, 2, 3, 23456}, true},
|
||||
{"00:00:00.000000001", Time{0, 0, 0, 1}, true},
|
||||
{"13:26:03.1", Time{13, 26, 3, 100000000}, false},
|
||||
{"13:26:33.0000003", Time{13, 26, 33, 300}, false},
|
||||
} {
|
||||
gotTime, err := ParseTime(test.str)
|
||||
if err != nil {
|
||||
t.Errorf("ParseTime(%q): got error: %v", test.str, err)
|
||||
continue
|
||||
}
|
||||
if gotTime != test.time {
|
||||
t.Errorf("ParseTime(%q) = %+v, want %+v", test.str, gotTime, test.time)
|
||||
}
|
||||
if test.roundTrip {
|
||||
gotStr := test.time.String()
|
||||
if gotStr != test.str {
|
||||
t.Errorf("%#v.String() = %q, want %q", test.time, gotStr, test.str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeOf(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
time time.Time
|
||||
want Time
|
||||
}{
|
||||
{time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local), Time{15, 8, 43, 1}},
|
||||
{time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), Time{0, 0, 0, 0}},
|
||||
} {
|
||||
if got := TimeOf(test.time); got != test.want {
|
||||
t.Errorf("TimeOf(%v) = %+v, want %+v", test.time, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeIsValid(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
time Time
|
||||
want bool
|
||||
}{
|
||||
{Time{0, 0, 0, 0}, true},
|
||||
{Time{23, 0, 0, 0}, true},
|
||||
{Time{23, 59, 59, 999999999}, true},
|
||||
{Time{24, 59, 59, 999999999}, false},
|
||||
{Time{23, 60, 59, 999999999}, false},
|
||||
{Time{23, 59, 60, 999999999}, false},
|
||||
{Time{23, 59, 59, 1000000000}, false},
|
||||
{Time{-1, 0, 0, 0}, false},
|
||||
{Time{0, -1, 0, 0}, false},
|
||||
{Time{0, 0, -1, 0}, false},
|
||||
{Time{0, 0, 0, -1}, false},
|
||||
} {
|
||||
got := test.time.IsValid()
|
||||
if got != test.want {
|
||||
t.Errorf("%#v: got %t, want %t", test.time, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeToString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
str string
|
||||
dateTime DateTime
|
||||
roundTrip bool // ParseDateTime(str).String() == str?
|
||||
}{
|
||||
{"2016-03-22T13:26:33", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 0}}, true},
|
||||
{"2016-03-22T13:26:33.000000600", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 600}}, true},
|
||||
{"2016-03-22t13:26:33", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 0}}, false},
|
||||
} {
|
||||
gotDateTime, err := ParseDateTime(test.str)
|
||||
if err != nil {
|
||||
t.Errorf("ParseDateTime(%q): got error: %v", test.str, err)
|
||||
continue
|
||||
}
|
||||
if gotDateTime != test.dateTime {
|
||||
t.Errorf("ParseDateTime(%q) = %+v, want %+v", test.str, gotDateTime, test.dateTime)
|
||||
}
|
||||
if test.roundTrip {
|
||||
gotStr := test.dateTime.String()
|
||||
if gotStr != test.str {
|
||||
t.Errorf("%#v.String() = %q, want %q", test.dateTime, gotStr, test.str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDateTimeErrors(t *testing.T) {
|
||||
for _, str := range []string{
|
||||
"",
|
||||
"2016-03-22", // just a date
|
||||
"13:26:33", // just a time
|
||||
"2016-03-22 13:26:33", // wrong separating character
|
||||
"2016-03-22T13:26:33x", // extra at end
|
||||
} {
|
||||
if _, err := ParseDateTime(str); err == nil {
|
||||
t.Errorf("ParseDateTime(%q) succeeded, want error", str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeOf(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
time time.Time
|
||||
want DateTime
|
||||
}{
|
||||
{time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local),
|
||||
DateTime{Date{2014, 8, 20}, Time{15, 8, 43, 1}}},
|
||||
{time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
DateTime{Date{1, 1, 1}, Time{0, 0, 0, 0}}},
|
||||
} {
|
||||
if got := DateTimeOf(test.time); got != test.want {
|
||||
t.Errorf("DateTimeOf(%v) = %+v, want %+v", test.time, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeIsValid(t *testing.T) {
|
||||
// No need to be exhaustive here; it's just Date.IsValid && Time.IsValid.
|
||||
for _, test := range []struct {
|
||||
dt DateTime
|
||||
want bool
|
||||
}{
|
||||
{DateTime{Date{2016, 3, 20}, Time{0, 0, 0, 0}}, true},
|
||||
{DateTime{Date{2016, -3, 20}, Time{0, 0, 0, 0}}, false},
|
||||
{DateTime{Date{2016, 3, 20}, Time{24, 0, 0, 0}}, false},
|
||||
} {
|
||||
got := test.dt.IsValid()
|
||||
if got != test.want {
|
||||
t.Errorf("%#v: got %t, want %t", test.dt, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeIn(t *testing.T) {
|
||||
dt := DateTime{Date{2016, 1, 2}, Time{3, 4, 5, 6}}
|
||||
got := dt.In(time.UTC)
|
||||
want := time.Date(2016, 1, 2, 3, 4, 5, 6, time.UTC)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeBefore(t *testing.T) {
|
||||
d1 := Date{2016, 12, 31}
|
||||
d2 := Date{2017, 1, 1}
|
||||
t1 := Time{5, 6, 7, 8}
|
||||
t2 := Time{5, 6, 7, 9}
|
||||
for _, test := range []struct {
|
||||
dt1, dt2 DateTime
|
||||
want bool
|
||||
}{
|
||||
{DateTime{d1, t1}, DateTime{d2, t1}, true},
|
||||
{DateTime{d1, t1}, DateTime{d1, t2}, true},
|
||||
{DateTime{d2, t1}, DateTime{d1, t1}, false},
|
||||
{DateTime{d2, t1}, DateTime{d2, t1}, false},
|
||||
} {
|
||||
if got := test.dt1.Before(test.dt2); got != test.want {
|
||||
t.Errorf("%v.Before(%v): got %t, want %t", test.dt1, test.dt2, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeAfter(t *testing.T) {
|
||||
d1 := Date{2016, 12, 31}
|
||||
d2 := Date{2017, 1, 1}
|
||||
t1 := Time{5, 6, 7, 8}
|
||||
t2 := Time{5, 6, 7, 9}
|
||||
for _, test := range []struct {
|
||||
dt1, dt2 DateTime
|
||||
want bool
|
||||
}{
|
||||
{DateTime{d1, t1}, DateTime{d2, t1}, false},
|
||||
{DateTime{d1, t1}, DateTime{d1, t2}, false},
|
||||
{DateTime{d2, t1}, DateTime{d1, t1}, true},
|
||||
{DateTime{d2, t1}, DateTime{d2, t1}, false},
|
||||
} {
|
||||
if got := test.dt1.After(test.dt2); got != test.want {
|
||||
t.Errorf("%v.After(%v): got %t, want %t", test.dt1, test.dt2, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value interface{}
|
||||
want string
|
||||
}{
|
||||
{Date{1987, 4, 15}, `"1987-04-15"`},
|
||||
{Time{18, 54, 2, 0}, `"18:54:02"`},
|
||||
{DateTime{Date{1987, 4, 15}, Time{18, 54, 2, 0}}, `"1987-04-15T18:54:02"`},
|
||||
} {
|
||||
bgot, err := json.Marshal(test.value)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(bgot); got != test.want {
|
||||
t.Errorf("%#v: got %s, want %s", test.value, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJSON(t *testing.T) {
|
||||
var d Date
|
||||
var tm Time
|
||||
var dt DateTime
|
||||
for _, test := range []struct {
|
||||
data string
|
||||
ptr interface{}
|
||||
want interface{}
|
||||
}{
|
||||
{`"1987-04-15"`, &d, &Date{1987, 4, 15}},
|
||||
{`"1987-04-\u0031\u0035"`, &d, &Date{1987, 4, 15}},
|
||||
{`"18:54:02"`, &tm, &Time{18, 54, 2, 0}},
|
||||
{`"1987-04-15T18:54:02"`, &dt, &DateTime{Date{1987, 4, 15}, Time{18, 54, 2, 0}}},
|
||||
} {
|
||||
if err := json.Unmarshal([]byte(test.data), test.ptr); err != nil {
|
||||
t.Fatalf("%s: %v", test.data, err)
|
||||
}
|
||||
if !cmp.Equal(test.ptr, test.want) {
|
||||
t.Errorf("%s: got %#v, want %#v", test.data, test.ptr, test.want)
|
||||
}
|
||||
}
|
||||
|
||||
for _, bad := range []string{"", `""`, `"bad"`, `"1987-04-15x"`,
|
||||
`19870415`, // a JSON number
|
||||
`11987-04-15x`, // not a JSON string
|
||||
|
||||
} {
|
||||
if json.Unmarshal([]byte(bad), &d) == nil {
|
||||
t.Errorf("%q, Date: got nil, want error", bad)
|
||||
}
|
||||
if json.Unmarshal([]byte(bad), &tm) == nil {
|
||||
t.Errorf("%q, Time: got nil, want error", bad)
|
||||
}
|
||||
if json.Unmarshal([]byte(bad), &dt) == nil {
|
||||
t.Errorf("%q, DateTime: got nil, want error", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
79
vendor/cloud.google.com/go/cloud.go
generated
vendored
79
vendor/cloud.google.com/go/cloud.go
generated
vendored
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright 2014 Google LLC
|
||||
//
|
||||
// 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 cloud is the root of the packages used to access Google Cloud
|
||||
Services. See https://godoc.org/cloud.google.com/go for a full list
|
||||
of sub-packages.
|
||||
|
||||
|
||||
Client Options
|
||||
|
||||
All clients in sub-packages are configurable via client options. These options are
|
||||
described here: https://godoc.org/google.golang.org/api/option.
|
||||
|
||||
|
||||
Authentication and Authorization
|
||||
|
||||
All the clients in sub-packages support authentication via Google Application Default
|
||||
Credentials (see https://cloud.google.com/docs/authentication/production), or
|
||||
by providing a JSON key file for a Service Account. See the authentication examples
|
||||
in this package for details.
|
||||
|
||||
|
||||
Timeouts and Cancellation
|
||||
|
||||
By default, all requests in sub-packages will run indefinitely, retrying on transient
|
||||
errors when correctness allows. To set timeouts or arrange for cancellation, use
|
||||
contexts. See the examples for details.
|
||||
|
||||
Do not attempt to control the initial connection (dialing) of a service by setting a
|
||||
timeout on the context passed to NewClient. Dialing is non-blocking, so timeouts
|
||||
would be ineffective and would only interfere with credential refreshing, which uses
|
||||
the same context.
|
||||
|
||||
|
||||
Connection Pooling
|
||||
|
||||
Connection pooling differs in clients based on their transport. Cloud
|
||||
clients either rely on HTTP or gRPC transports to communicate
|
||||
with Google Cloud.
|
||||
|
||||
Cloud clients that use HTTP (bigquery, compute, storage, and translate) rely on the
|
||||
underlying HTTP transport to cache connections for later re-use. These are cached to
|
||||
the default http.MaxIdleConns and http.MaxIdleConnsPerHost settings in
|
||||
http.DefaultTransport.
|
||||
|
||||
For gRPC clients (all others in this repo), connection pooling is configurable. Users
|
||||
of cloud client libraries may specify option.WithGRPCConnectionPool(n) as a client
|
||||
option to NewClient calls. This configures the underlying gRPC connections to be
|
||||
pooled and addressed in a round robin fashion.
|
||||
|
||||
|
||||
Using the Libraries with Docker
|
||||
|
||||
Minimal docker images like Alpine lack CA certificates. This causes RPCs to appear to
|
||||
hang, because gRPC retries indefinitely. See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/928
|
||||
for more information.
|
||||
|
||||
|
||||
Debugging
|
||||
|
||||
To see gRPC logs, set the environment variable GRPC_GO_LOG_SEVERITY_LEVEL. See
|
||||
https://godoc.org/google.golang.org/grpc/grpclog for more information.
|
||||
|
||||
For HTTP logging, set the GODEBUG environment variable to "http2debug=1" or "http2debug=2".
|
||||
|
||||
*/
|
||||
package cloud // import "cloud.google.com/go"
|
||||
60
vendor/cloud.google.com/go/examples_test.go
generated
vendored
60
vendor/cloud.google.com/go/examples_test.go
generated
vendored
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// 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 cloud_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/bigquery"
|
||||
)
|
||||
|
||||
// To set a timeout for an RPC, use context.WithTimeout.
|
||||
func Example_timeout() {
|
||||
ctx := context.Background()
|
||||
// Do not set a timeout on the context passed to NewClient: dialing happens
|
||||
// asynchronously, and the context is used to refresh credentials in the
|
||||
// background.
|
||||
client, err := bigquery.NewClient(ctx, "project-id")
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
// Time out if it takes more than 10 seconds to create a dataset.
|
||||
tctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel() // Always call cancel.
|
||||
|
||||
if err := client.Dataset("new-dataset").Create(tctx, nil); err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
}
|
||||
|
||||
// To arrange for an RPC to be canceled, use context.WithCancel.
|
||||
func Example_cancellation() {
|
||||
ctx := context.Background()
|
||||
// Do not cancel the context passed to NewClient: dialing happens asynchronously,
|
||||
// and the context is used to refresh credentials in the background.
|
||||
client, err := bigquery.NewClient(ctx, "project-id")
|
||||
if err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
cctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel() // Always call cancel.
|
||||
|
||||
// TODO: Make the cancel function available to whatever might want to cancel the
|
||||
// call--perhaps a GUI button.
|
||||
if err := client.Dataset("new-dataset").Create(cctx, nil); err != nil {
|
||||
// TODO: handle error.
|
||||
}
|
||||
}
|
||||
17
vendor/cloud.google.com/go/issue_template.md
generated
vendored
17
vendor/cloud.google.com/go/issue_template.md
generated
vendored
|
|
@ -1,17 +0,0 @@
|
|||
(delete this for feature requests)
|
||||
|
||||
## Client
|
||||
|
||||
e.g. PubSub
|
||||
|
||||
## Describe Your Environment
|
||||
|
||||
e.g. Alpine Docker on GKE
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
e.g. Messages arrive really fast.
|
||||
|
||||
## Actual Behavior
|
||||
|
||||
e.g. Messages arrive really slowly.
|
||||
BIN
vendor/cloud.google.com/go/keys.tar.enc
generated
vendored
BIN
vendor/cloud.google.com/go/keys.tar.enc
generated
vendored
Binary file not shown.
74
vendor/cloud.google.com/go/license_test.go
generated
vendored
74
vendor/cloud.google.com/go/license_test.go
generated
vendored
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// 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 cloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var sentinels = []string{
|
||||
"Copyright",
|
||||
"Google",
|
||||
`Licensed under the Apache License, Version 2.0 (the "License");`,
|
||||
}
|
||||
|
||||
func TestLicense(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" {
|
||||
return nil
|
||||
}
|
||||
if strings.HasSuffix(path, ".pb.go") {
|
||||
// .pb.go files are generated from the proto files.
|
||||
// .proto files must have license headers.
|
||||
return nil
|
||||
}
|
||||
if path == "bigtable/cmd/cbt/cbtdoc.go" {
|
||||
// Automatically generated.
|
||||
return nil
|
||||
}
|
||||
if path == "cmd/go-cloud-debug-agent/internal/debug/elf/elf.go" {
|
||||
// BSD license, which is compatible, is embedded in the file.
|
||||
return nil
|
||||
}
|
||||
src, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
src = src[:300] // Ensure all of the sentinel values are at the top of the file.
|
||||
|
||||
// Find license
|
||||
for _, sentinel := range sentinels {
|
||||
if !bytes.Contains(src, []byte(sentinel)) {
|
||||
t.Errorf("%v: license header not present. want %q", path, sentinel)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
698
vendor/cloud.google.com/go/old-news.md
generated
vendored
698
vendor/cloud.google.com/go/old-news.md
generated
vendored
|
|
@ -1,698 +0,0 @@
|
|||
_February 26, 2018_
|
||||
|
||||
*v0.19.0*
|
||||
|
||||
- bigquery:
|
||||
- Support customer-managed encryption keys.
|
||||
|
||||
- bigtable:
|
||||
- Improved emulator support.
|
||||
- Support GetCluster.
|
||||
|
||||
- datastore:
|
||||
- Add general mutations.
|
||||
- Support pointer struct fields.
|
||||
- Support transaction options.
|
||||
|
||||
- firestore:
|
||||
- Add Transaction.GetAll.
|
||||
- Support document cursors.
|
||||
|
||||
- logging:
|
||||
- Support concurrent RPCs to the service.
|
||||
- Support per-entry resources.
|
||||
|
||||
- profiler:
|
||||
- Add config options to disable heap and thread profiling.
|
||||
- Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set.
|
||||
|
||||
- pubsub:
|
||||
- BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the
|
||||
callback returns).
|
||||
- Add SubscriptionInProject.
|
||||
- Add OpenCensus instrumentation for streaming pull.
|
||||
|
||||
- storage:
|
||||
- Support CORS.
|
||||
|
||||
|
||||
_January 18, 2018_
|
||||
|
||||
*v0.18.0*
|
||||
|
||||
- bigquery:
|
||||
- Marked stable.
|
||||
- Schema inference of nullable fields supported.
|
||||
- Added TimePartitioning to QueryConfig.
|
||||
|
||||
- firestore: Data provided to DocumentRef.Set with a Merge option can contain
|
||||
Delete sentinels.
|
||||
|
||||
- logging: Clients can accept parent resources other than projects.
|
||||
|
||||
- pubsub:
|
||||
- pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome.
|
||||
- Support updating more subscription metadata: AckDeadline,
|
||||
RetainAckedMessages and RetentionDuration.
|
||||
|
||||
- oslogin/apiv1beta: New client for the Cloud OS Login API.
|
||||
|
||||
- rpcreplay: A package for recording and replaying gRPC traffic.
|
||||
|
||||
- spanner:
|
||||
- Add a ReadWithOptions that supports a row limit, as well as an index.
|
||||
- Support query plan and execution statistics.
|
||||
- Added [OpenCensus](http://opencensus.io) support.
|
||||
|
||||
- storage: Clarify checksum validation for gzipped files (it is not validated
|
||||
when the file is served uncompressed).
|
||||
|
||||
|
||||
_December 11, 2017_
|
||||
|
||||
*v0.17.0*
|
||||
|
||||
- firestore BREAKING CHANGES:
|
||||
- Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update.
|
||||
Change
|
||||
`docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})`
|
||||
to
|
||||
`docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})`
|
||||
|
||||
Change
|
||||
`docref.UpdateStruct(ctx, []string{"Field"}, aStruct)`
|
||||
to
|
||||
`docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})`
|
||||
- Rename MergePaths to Merge; require args to be FieldPaths
|
||||
- A value stored as an integer can be read into a floating-point field, and vice versa.
|
||||
- bigtable/cmd/cbt:
|
||||
- Support deleting a column.
|
||||
- Add regex option for row read.
|
||||
- spanner: Mark stable.
|
||||
- storage:
|
||||
- Add Reader.ContentEncoding method.
|
||||
- Fix handling of SignedURL headers.
|
||||
- bigquery:
|
||||
- If Uploader.Put is called with no rows, it returns nil without making a
|
||||
call.
|
||||
- Schema inference supports the "nullable" option in struct tags for
|
||||
non-required fields.
|
||||
- TimePartitioning supports "Field".
|
||||
|
||||
|
||||
_October 30, 2017_
|
||||
|
||||
*v0.16.0*
|
||||
|
||||
- Other bigquery changes:
|
||||
- `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE).
|
||||
- UseStandardSQL is deprecated; set UseLegacySQL to true if you need
|
||||
Legacy SQL.
|
||||
- Uploader.Put will generate a random insert ID if you do not provide one.
|
||||
- Support time partitioning for load jobs.
|
||||
- Support dry-run queries.
|
||||
- A `Job` remembers its last retrieved status.
|
||||
- Support retrieving job configuration.
|
||||
- Support labels for jobs and tables.
|
||||
- Support dataset access lists.
|
||||
- Improve support for external data sources, including data from Bigtable and
|
||||
Google Sheets, and tables with external data.
|
||||
- Support updating a table's view configuration.
|
||||
- Fix uploading civil times with nanoseconds.
|
||||
|
||||
- storage:
|
||||
- Support PubSub notifications.
|
||||
- Support Requester Pays buckets.
|
||||
|
||||
- profiler: Support goroutine and mutex profile types.
|
||||
|
||||
|
||||
_October 3, 2017_
|
||||
|
||||
*v0.15.0*
|
||||
|
||||
- firestore: beta release. See the
|
||||
[announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html).
|
||||
|
||||
- errorreporting: The existing package has been redesigned.
|
||||
|
||||
- errors: This package has been removed. Use errorreporting.
|
||||
|
||||
|
||||
_September 28, 2017_
|
||||
|
||||
*v0.14.0*
|
||||
|
||||
- bigquery BREAKING CHANGES:
|
||||
- Standard SQL is the default for queries and views.
|
||||
- `Table.Create` takes `TableMetadata` as a second argument, instead of
|
||||
options.
|
||||
- `Dataset.Create` takes `DatasetMetadata` as a second argument.
|
||||
- `DatasetMetadata` field `ID` renamed to `FullID`
|
||||
- `TableMetadata` field `ID` renamed to `FullID`
|
||||
|
||||
- Other bigquery changes:
|
||||
- The client will append a random suffix to a provided job ID if you set
|
||||
`AddJobIDSuffix` to true in a job config.
|
||||
- Listing jobs is supported.
|
||||
- Better retry logic.
|
||||
|
||||
- vision, language, speech: clients are now stable
|
||||
|
||||
- monitoring: client is now beta
|
||||
|
||||
- profiler:
|
||||
- Rename InstanceName to Instance, ZoneName to Zone
|
||||
- Auto-detect service name and version on AppEngine.
|
||||
|
||||
_September 8, 2017_
|
||||
|
||||
*v0.13.0*
|
||||
|
||||
- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these
|
||||
options to continue using Legacy SQL after the client switches its default
|
||||
to Standard SQL.
|
||||
|
||||
- bigquery: Support for updating dataset labels.
|
||||
|
||||
- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other
|
||||
than the client's. DatasetsInProject is no longer needed and is deprecated.
|
||||
|
||||
- bigtable: Fail ListInstances when any zones fail.
|
||||
|
||||
- spanner: support decoding of slices of basic types (e.g. []string, []int64,
|
||||
etc.)
|
||||
|
||||
- logging/logadmin: UpdateSink no longer creates a sink if it is missing
|
||||
(actually a change to the underlying service, not the client)
|
||||
|
||||
- profiler: Service and ServiceVersion replace Target in Config.
|
||||
|
||||
_August 22, 2017_
|
||||
|
||||
*v0.12.0*
|
||||
|
||||
- pubsub: Subscription.Receive now uses streaming pull.
|
||||
|
||||
- pubsub: add Client.TopicInProject to access topics in a different project
|
||||
than the client.
|
||||
|
||||
- errors: renamed errorreporting. The errors package will be removed shortly.
|
||||
|
||||
- datastore: improved retry behavior.
|
||||
|
||||
- bigquery: support updates to dataset metadata, with etags.
|
||||
|
||||
- bigquery: add etag support to Table.Update (BREAKING: etag argument added).
|
||||
|
||||
- bigquery: generate all job IDs on the client.
|
||||
|
||||
- storage: support bucket lifecycle configurations.
|
||||
|
||||
|
||||
_July 31, 2017_
|
||||
|
||||
*v0.11.0*
|
||||
|
||||
- Clients for spanner, pubsub and video are now in beta.
|
||||
|
||||
- New client for DLP.
|
||||
|
||||
- spanner: performance and testing improvements.
|
||||
|
||||
- storage: requester-pays buckets are supported.
|
||||
|
||||
- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements.
|
||||
|
||||
- pubsub: bug fixes and other minor improvements
|
||||
|
||||
_June 17, 2017_
|
||||
|
||||
|
||||
*v0.10.0*
|
||||
|
||||
- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update.
|
||||
|
||||
- pubsub: Subscription.Receive now runs concurrently for higher throughput.
|
||||
|
||||
- vision: cloud.google.com/go/vision is deprecated. Use
|
||||
cloud.google.com/go/vision/apiv1 instead.
|
||||
|
||||
- translation: now stable.
|
||||
|
||||
- trace: several changes to the surface. See the link below.
|
||||
|
||||
[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md)
|
||||
|
||||
|
||||
_March 17, 2017_
|
||||
|
||||
Breaking Pubsub changes.
|
||||
* Publish is now asynchronous
|
||||
([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)).
|
||||
* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)).
|
||||
* Message.Done replaced with Message.Ack and Message.Nack.
|
||||
|
||||
_February 14, 2017_
|
||||
|
||||
Release of a client library for Spanner. See
|
||||
the
|
||||
[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html).
|
||||
|
||||
Note that although the Spanner service is beta, the Go client library is alpha.
|
||||
|
||||
_December 12, 2016_
|
||||
|
||||
Beta release of BigQuery, DataStore, Logging and Storage. See the
|
||||
[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html).
|
||||
|
||||
Also, BigQuery now supports structs. Read a row directly into a struct with
|
||||
`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`.
|
||||
You can also use field tags. See the [package documentation][cloud-bigquery-ref]
|
||||
for details.
|
||||
|
||||
_December 5, 2016_
|
||||
|
||||
More changes to BigQuery:
|
||||
|
||||
* The `ValueList` type was removed. It is no longer necessary. Instead of
|
||||
```go
|
||||
var v ValueList
|
||||
... it.Next(&v) ..
|
||||
```
|
||||
use
|
||||
|
||||
```go
|
||||
var v []Value
|
||||
... it.Next(&v) ...
|
||||
```
|
||||
|
||||
* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or
|
||||
`ValueList` would append to the slice. Now each call resets the size to zero first.
|
||||
|
||||
* Schema inference will infer the SQL type BYTES for a struct field of
|
||||
type []byte. Previously it inferred STRING.
|
||||
|
||||
* The types `uint`, `uint64` and `uintptr` are no longer supported in schema
|
||||
inference. BigQuery's integer type is INT64, and those types may hold values
|
||||
that are not correctly represented in a 64-bit signed integer.
|
||||
|
||||
* The SQL types DATE, TIME and DATETIME are now supported. They correspond to
|
||||
the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil`
|
||||
package.
|
||||
|
||||
_November 17, 2016_
|
||||
|
||||
Change to BigQuery: values from INTEGER columns will now be returned as int64,
|
||||
not int. This will avoid errors arising from large values on 32-bit systems.
|
||||
|
||||
_November 8, 2016_
|
||||
|
||||
New datastore feature: datastore now encodes your nested Go structs as Entity values,
|
||||
instead of a flattened list of the embedded struct's fields.
|
||||
This means that you may now have twice-nested slices, eg.
|
||||
```go
|
||||
type State struct {
|
||||
Cities []struct{
|
||||
Populations []int
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for
|
||||
more details.
|
||||
|
||||
_November 8, 2016_
|
||||
|
||||
Breaking changes to datastore: contexts no longer hold namespaces; instead you
|
||||
must set a key's namespace explicitly. Also, key functions have been changed
|
||||
and renamed.
|
||||
|
||||
* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method:
|
||||
```go
|
||||
q := datastore.NewQuery("Kind").Namespace("ns")
|
||||
```
|
||||
|
||||
* All the fields of Key are exported. That means you can construct any Key with a struct literal:
|
||||
```go
|
||||
k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"}
|
||||
```
|
||||
|
||||
* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed.
|
||||
|
||||
* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace
|
||||
```go
|
||||
NewIncompleteKey(ctx, kind, parent)
|
||||
```
|
||||
with
|
||||
```go
|
||||
IncompleteKey(kind, parent)
|
||||
```
|
||||
and if you do use namespaces, make sure you set the namespace on the returned key.
|
||||
|
||||
* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace
|
||||
```go
|
||||
NewKey(ctx, kind, name, 0, parent)
|
||||
NewKey(ctx, kind, "", id, parent)
|
||||
```
|
||||
with
|
||||
```go
|
||||
NameKey(kind, name, parent)
|
||||
IDKey(kind, id, parent)
|
||||
```
|
||||
and if you do use namespaces, make sure you set the namespace on the returned key.
|
||||
|
||||
* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`.
|
||||
|
||||
* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection.
|
||||
|
||||
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for
|
||||
more details.
|
||||
|
||||
_October 27, 2016_
|
||||
|
||||
Breaking change to bigquery: `NewGCSReference` is now a function,
|
||||
not a method on `Client`.
|
||||
|
||||
New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling
|
||||
loading data into a table from a file or any `io.Reader`.
|
||||
|
||||
_October 21, 2016_
|
||||
|
||||
Breaking change to pubsub: removed `pubsub.Done`.
|
||||
|
||||
Use `iterator.Done` instead, where `iterator` is the package
|
||||
`google.golang.org/api/iterator`.
|
||||
|
||||
_October 19, 2016_
|
||||
|
||||
Breaking changes to cloud.google.com/go/bigquery:
|
||||
|
||||
* Client.Table and Client.OpenTable have been removed.
|
||||
Replace
|
||||
```go
|
||||
client.OpenTable("project", "dataset", "table")
|
||||
```
|
||||
with
|
||||
```go
|
||||
client.DatasetInProject("project", "dataset").Table("table")
|
||||
```
|
||||
|
||||
* Client.CreateTable has been removed.
|
||||
Replace
|
||||
```go
|
||||
client.CreateTable(ctx, "project", "dataset", "table")
|
||||
```
|
||||
with
|
||||
```go
|
||||
client.DatasetInProject("project", "dataset").Table("table").Create(ctx)
|
||||
```
|
||||
|
||||
* Dataset.ListTables have been replaced with Dataset.Tables.
|
||||
Replace
|
||||
```go
|
||||
tables, err := ds.ListTables(ctx)
|
||||
```
|
||||
with
|
||||
```go
|
||||
it := ds.Tables(ctx)
|
||||
for {
|
||||
table, err := it.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// TODO: use table.
|
||||
}
|
||||
```
|
||||
|
||||
* Client.Read has been replaced with Job.Read, Table.Read and Query.Read.
|
||||
Replace
|
||||
```go
|
||||
it, err := client.Read(ctx, job)
|
||||
```
|
||||
with
|
||||
```go
|
||||
it, err := job.Read(ctx)
|
||||
```
|
||||
and similarly for reading from tables or queries.
|
||||
|
||||
* The iterator returned from the Read methods is now named RowIterator. Its
|
||||
behavior is closer to the other iterators in these libraries. It no longer
|
||||
supports the Schema method; see the next item.
|
||||
Replace
|
||||
```go
|
||||
for it.Next(ctx) {
|
||||
var vals ValueList
|
||||
if err := it.Get(&vals); err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// TODO: use vals.
|
||||
}
|
||||
if err := it.Err(); err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
with
|
||||
```
|
||||
for {
|
||||
var vals ValueList
|
||||
err := it.Next(&vals)
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// TODO: use vals.
|
||||
}
|
||||
```
|
||||
Instead of the `RecordsPerRequest(n)` option, write
|
||||
```go
|
||||
it.PageInfo().MaxSize = n
|
||||
```
|
||||
Instead of the `StartIndex(i)` option, write
|
||||
```go
|
||||
it.StartIndex = i
|
||||
```
|
||||
|
||||
* ValueLoader.Load now takes a Schema in addition to a slice of Values.
|
||||
Replace
|
||||
```go
|
||||
func (vl *myValueLoader) Load(v []bigquery.Value)
|
||||
```
|
||||
with
|
||||
```go
|
||||
func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema)
|
||||
```
|
||||
|
||||
|
||||
* Table.Patch is replace by Table.Update.
|
||||
Replace
|
||||
```go
|
||||
p := table.Patch()
|
||||
p.Description("new description")
|
||||
metadata, err := p.Apply(ctx)
|
||||
```
|
||||
with
|
||||
```go
|
||||
metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{
|
||||
Description: "new description",
|
||||
})
|
||||
```
|
||||
|
||||
* Client.Copy is replaced by separate methods for each of its four functions.
|
||||
All options have been replaced by struct fields.
|
||||
|
||||
* To load data from Google Cloud Storage into a table, use Table.LoaderFrom.
|
||||
|
||||
Replace
|
||||
```go
|
||||
client.Copy(ctx, table, gcsRef)
|
||||
```
|
||||
with
|
||||
```go
|
||||
table.LoaderFrom(gcsRef).Run(ctx)
|
||||
```
|
||||
Instead of passing options to Copy, set fields on the Loader:
|
||||
```go
|
||||
loader := table.LoaderFrom(gcsRef)
|
||||
loader.WriteDisposition = bigquery.WriteTruncate
|
||||
```
|
||||
|
||||
* To extract data from a table into Google Cloud Storage, use
|
||||
Table.ExtractorTo. Set fields on the returned Extractor instead of
|
||||
passing options.
|
||||
|
||||
Replace
|
||||
```go
|
||||
client.Copy(ctx, gcsRef, table)
|
||||
```
|
||||
with
|
||||
```go
|
||||
table.ExtractorTo(gcsRef).Run(ctx)
|
||||
```
|
||||
|
||||
* To copy data into a table from one or more other tables, use
|
||||
Table.CopierFrom. Set fields on the returned Copier instead of passing options.
|
||||
|
||||
Replace
|
||||
```go
|
||||
client.Copy(ctx, dstTable, srcTable)
|
||||
```
|
||||
with
|
||||
```go
|
||||
dst.Table.CopierFrom(srcTable).Run(ctx)
|
||||
```
|
||||
|
||||
* To start a query job, create a Query and call its Run method. Set fields
|
||||
on the query instead of passing options.
|
||||
|
||||
Replace
|
||||
```go
|
||||
client.Copy(ctx, table, query)
|
||||
```
|
||||
with
|
||||
```go
|
||||
query.Run(ctx)
|
||||
```
|
||||
|
||||
* Table.NewUploader has been renamed to Table.Uploader. Instead of options,
|
||||
configure an Uploader by setting its fields.
|
||||
Replace
|
||||
```go
|
||||
u := table.NewUploader(bigquery.UploadIgnoreUnknownValues())
|
||||
```
|
||||
with
|
||||
```go
|
||||
u := table.NewUploader(bigquery.UploadIgnoreUnknownValues())
|
||||
u.IgnoreUnknownValues = true
|
||||
```
|
||||
|
||||
_October 10, 2016_
|
||||
|
||||
Breaking changes to cloud.google.com/go/storage:
|
||||
|
||||
* AdminClient replaced by methods on Client.
|
||||
Replace
|
||||
```go
|
||||
adminClient.CreateBucket(ctx, bucketName, attrs)
|
||||
```
|
||||
with
|
||||
```go
|
||||
client.Bucket(bucketName).Create(ctx, projectID, attrs)
|
||||
```
|
||||
|
||||
* BucketHandle.List replaced by BucketHandle.Objects.
|
||||
Replace
|
||||
```go
|
||||
for query != nil {
|
||||
objs, err := bucket.List(d.ctx, query)
|
||||
if err != nil { ... }
|
||||
query = objs.Next
|
||||
for _, obj := range objs.Results {
|
||||
fmt.Println(obj)
|
||||
}
|
||||
}
|
||||
```
|
||||
with
|
||||
```go
|
||||
iter := bucket.Objects(d.ctx, query)
|
||||
for {
|
||||
obj, err := iter.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil { ... }
|
||||
fmt.Println(obj)
|
||||
}
|
||||
```
|
||||
(The `iterator` package is at `google.golang.org/api/iterator`.)
|
||||
|
||||
Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`.
|
||||
|
||||
Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`.
|
||||
|
||||
|
||||
* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom.
|
||||
Replace
|
||||
```go
|
||||
attrs, err := src.CopyTo(ctx, dst, nil)
|
||||
```
|
||||
with
|
||||
```go
|
||||
attrs, err := dst.CopierFrom(src).Run(ctx)
|
||||
```
|
||||
|
||||
Replace
|
||||
```go
|
||||
attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"})
|
||||
```
|
||||
with
|
||||
```go
|
||||
c := dst.CopierFrom(src)
|
||||
c.ContextType = "text/html"
|
||||
attrs, err := c.Run(ctx)
|
||||
```
|
||||
|
||||
* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom.
|
||||
Replace
|
||||
```go
|
||||
attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil)
|
||||
```
|
||||
with
|
||||
```go
|
||||
attrs, err := dst.ComposerFrom(src1, src2).Run(ctx)
|
||||
```
|
||||
|
||||
* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate.
|
||||
Replace
|
||||
```go
|
||||
attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"})
|
||||
```
|
||||
with
|
||||
```go
|
||||
attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"})
|
||||
```
|
||||
|
||||
* ObjectHandle.WithConditions replaced by ObjectHandle.If.
|
||||
Replace
|
||||
```go
|
||||
obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen))
|
||||
```
|
||||
with
|
||||
```go
|
||||
obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen})
|
||||
```
|
||||
|
||||
Replace
|
||||
```go
|
||||
obj.WithConditions(storage.IfGenerationMatch(0))
|
||||
```
|
||||
with
|
||||
```go
|
||||
obj.If(storage.Conditions{DoesNotExist: true})
|
||||
```
|
||||
|
||||
* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`).
|
||||
|
||||
_October 6, 2016_
|
||||
|
||||
Package preview/logging deleted. Use logging instead.
|
||||
|
||||
_September 27, 2016_
|
||||
|
||||
Logging client replaced with preview version (see below).
|
||||
|
||||
_September 8, 2016_
|
||||
|
||||
* New clients for some of Google's Machine Learning APIs: Vision, Speech, and
|
||||
Natural Language.
|
||||
|
||||
* Preview version of a new [Stackdriver Logging][cloud-logging] client in
|
||||
[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging).
|
||||
This client uses gRPC as its transport layer, and supports log reading, sinks
|
||||
and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly.
|
||||
|
||||
86
vendor/cloud.google.com/go/regen-gapic.sh
generated
vendored
86
vendor/cloud.google.com/go/regen-gapic.sh
generated
vendored
|
|
@ -1,86 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script generates all GAPIC clients in this repo.
|
||||
# One-time setup:
|
||||
# cd path/to/googleapis # https://github.com/googleapis/googleapis
|
||||
# virtualenv env
|
||||
# . env/bin/activate
|
||||
# pip install googleapis-artman
|
||||
# deactivate
|
||||
#
|
||||
# Regenerate:
|
||||
# cd path/to/googleapis
|
||||
# . env/bin/activate
|
||||
# $GOPATH/src/cloud.google.com/go/regen-gapic.sh
|
||||
# deactivate
|
||||
#
|
||||
# Being in googleapis directory is important;
|
||||
# that's where we find YAML files and where artman puts the "artman-genfiles" directory.
|
||||
#
|
||||
# NOTE: This script does not generate the "raw" gRPC client found in google.golang.org/genproto.
|
||||
# To do that, use the regen.sh script in the genproto repo instead.
|
||||
|
||||
set -ex
|
||||
|
||||
APIS=(
|
||||
google/api/expr/artman_cel.yaml
|
||||
google/iam/artman_iam_admin.yaml
|
||||
google/cloud/asset/artman_cloudasset_v1beta1.yaml
|
||||
google/iam/credentials/artman_iamcredentials_v1.yaml
|
||||
google/cloud/bigquery/datatransfer/artman_bigquerydatatransfer.yaml
|
||||
google/cloud/dataproc/artman_dataproc_v1.yaml
|
||||
google/cloud/dataproc/artman_dataproc_v1beta2.yaml
|
||||
google/cloud/dialogflow/artman_dialogflow_v2.yaml
|
||||
google/cloud/kms/artman_cloudkms.yaml
|
||||
google/cloud/language/artman_language_v1.yaml
|
||||
google/cloud/language/artman_language_v1beta2.yaml
|
||||
google/cloud/oslogin/artman_oslogin_v1.yaml
|
||||
google/cloud/oslogin/artman_oslogin_v1beta.yaml
|
||||
google/cloud/redis/artman_redis_v1beta1.yaml
|
||||
google/cloud/redis/artman_redis_v1.yaml
|
||||
google/cloud/scheduler/artman_cloudscheduler_v1beta1.yaml
|
||||
google/cloud/securitycenter/artman_securitycenter_v1beta1.yaml
|
||||
google/cloud/speech/artman_speech_v1.yaml
|
||||
google/cloud/speech/artman_speech_v1p1beta1.yaml
|
||||
google/cloud/tasks/artman_cloudtasks_v2beta2.yaml
|
||||
google/cloud/tasks/artman_cloudtasks_v2beta3.yaml
|
||||
google/cloud/texttospeech/artman_texttospeech_v1.yaml
|
||||
google/cloud/videointelligence/artman_videointelligence_v1.yaml
|
||||
google/cloud/videointelligence/artman_videointelligence_v1beta1.yaml
|
||||
google/cloud/videointelligence/artman_videointelligence_v1beta2.yaml
|
||||
google/cloud/vision/artman_vision_v1.yaml
|
||||
google/cloud/vision/artman_vision_v1p1beta1.yaml
|
||||
google/devtools/artman_clouddebugger.yaml
|
||||
google/devtools/clouderrorreporting/artman_errorreporting.yaml
|
||||
google/devtools/cloudtrace/artman_cloudtrace_v1.yaml
|
||||
google/devtools/cloudtrace/artman_cloudtrace_v2.yaml
|
||||
google/devtools/containeranalysis/artman_containeranalysis_v1beta1.yaml
|
||||
google/firestore/artman_firestore.yaml
|
||||
google/logging/artman_logging.yaml
|
||||
google/longrunning/artman_longrunning.yaml
|
||||
google/monitoring/artman_monitoring.yaml
|
||||
google/privacy/dlp/artman_dlp_v2.yaml
|
||||
google/pubsub/artman_pubsub.yaml
|
||||
google/spanner/admin/database/artman_spanner_admin_database.yaml
|
||||
google/spanner/admin/instance/artman_spanner_admin_instance.yaml
|
||||
google/spanner/artman_spanner.yaml
|
||||
)
|
||||
|
||||
for api in "${APIS[@]}"; do
|
||||
rm -rf artman-genfiles/*
|
||||
artman --config "$api" generate go_gapic
|
||||
cp -r artman-genfiles/gapi-*/cloud.google.com/go/* $GOPATH/src/cloud.google.com/go/
|
||||
done
|
||||
|
||||
# NOTE(pongad): `sed -i` doesn't work on Macs, because -i option needs an argument.
|
||||
# `-i ''` doesn't work on GNU, since the empty string is treated as a file name.
|
||||
# So we just create the backup and delete it after.
|
||||
ver=$(date +%Y%m%d)
|
||||
find $GOPATH/src/cloud.google.com/go/ -name '*.go' -exec sed -i.backup -e "s/^const versionClient.*/const versionClient = \"$ver\"/" '{}' +
|
||||
find $GOPATH/src/cloud.google.com/go/ -name '*.backup' -delete
|
||||
|
||||
#go list cloud.google.com/go/... | grep apiv | xargs go test
|
||||
|
||||
#go test -short cloud.google.com/go/...
|
||||
|
||||
#echo "googleapis version: $(git rev-parse HEAD)"
|
||||
88
vendor/cloud.google.com/go/run-tests.sh
generated
vendored
88
vendor/cloud.google.com/go/run-tests.sh
generated
vendored
|
|
@ -1,88 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Selectively run tests for this repo, based on what has changed
|
||||
# in a commit. Runs short tests for the whole repo, and full tests
|
||||
# for changed directories.
|
||||
|
||||
set -e
|
||||
|
||||
prefix=cloud.google.com/go
|
||||
|
||||
dryrun=false
|
||||
if [[ $1 == "-n" ]]; then
|
||||
dryrun=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if [[ $1 == "" ]]; then
|
||||
echo >&2 "usage: $0 [-n] COMMIT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Files or directories that cause all tests to run if modified.
|
||||
declare -A run_all
|
||||
run_all=([.travis.yml]=1 [run-tests.sh]=1)
|
||||
|
||||
function run {
|
||||
if $dryrun; then
|
||||
echo $*
|
||||
else
|
||||
(set -x; $*)
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Find all the packages that have changed in this commit.
|
||||
declare -A changed_packages
|
||||
|
||||
for f in $(git diff-tree --no-commit-id --name-only -r $1); do
|
||||
if [[ ${run_all[$f]} == 1 ]]; then
|
||||
# This change requires a full test. Do it and exit.
|
||||
run go test -race -v $prefix/...
|
||||
exit
|
||||
fi
|
||||
# Map, e.g., "spanner/client.go" to "$prefix/spanner".
|
||||
d=$(dirname $f)
|
||||
if [[ $d == "." ]]; then
|
||||
pkg=$prefix
|
||||
else
|
||||
pkg=$prefix/$d
|
||||
fi
|
||||
changed_packages[$pkg]=1
|
||||
done
|
||||
|
||||
echo "changed packages: ${!changed_packages[*]}"
|
||||
|
||||
|
||||
# Reports whether its argument, a package name, depends (recursively)
|
||||
# on a changed package.
|
||||
function depends_on_changed_package {
|
||||
# According to go list, a package does not depend on itself, so
|
||||
# we test that separately.
|
||||
if [[ ${changed_packages[$1]} == 1 ]]; then
|
||||
return 0
|
||||
fi
|
||||
for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do
|
||||
if [[ ${changed_packages[$dep]} == 1 ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Collect the packages into two separate lists. (It is faster to call "go test" on a
|
||||
# list of packages than to individually "go test" each one.)
|
||||
|
||||
shorts=
|
||||
fulls=
|
||||
for pkg in $(go list $prefix/...); do # for each package in the repo
|
||||
if depends_on_changed_package $pkg; then # if it depends on a changed package
|
||||
fulls="$fulls $pkg" # run the full test
|
||||
else # otherwise
|
||||
shorts="$shorts $pkg" # run the short test
|
||||
fi
|
||||
done
|
||||
run go test -race -v -short $shorts
|
||||
if [[ $fulls != "" ]]; then
|
||||
run go test -race -v $fulls
|
||||
fi
|
||||
24
vendor/contrib.go.opencensus.io/exporter/ocagent/CONTRIBUTING.md
generated
vendored
24
vendor/contrib.go.opencensus.io/exporter/ocagent/CONTRIBUTING.md
generated
vendored
|
|
@ -1,24 +0,0 @@
|
|||
# How to contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution,
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult [GitHub Help] for more
|
||||
information on using pull requests.
|
||||
|
||||
[GitHub Help]: https://help.github.com/articles/about-pull-requests/
|
||||
61
vendor/contrib.go.opencensus.io/exporter/ocagent/README.md
generated
vendored
61
vendor/contrib.go.opencensus.io/exporter/ocagent/README.md
generated
vendored
|
|
@ -1,61 +0,0 @@
|
|||
# OpenCensus Agent Go Exporter
|
||||
|
||||
[![Build Status][travis-image]][travis-url] [![GoDoc][godoc-image]][godoc-url]
|
||||
|
||||
|
||||
This repository contains the Go implementation of the OpenCensus Agent (OC-Agent) Exporter.
|
||||
OC-Agent is a deamon process running in a VM that can retrieve spans/stats/metrics from
|
||||
OpenCensus Library, export them to other backends and possibly push configurations back to
|
||||
Library. See more details on [OC-Agent Readme][OCAgentReadme].
|
||||
|
||||
Note: This is an experimental repository and is likely to get backwards-incompatible changes.
|
||||
Ultimately we may want to move the OC-Agent Go Exporter to [OpenCensus Go core library][OpenCensusGo].
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ go get -u contrib.go.opencensus.io/exporter/ocagent/v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/ocagent/v1"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
exp, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName("your-service-name"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create the agent exporter: %v", err)
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
// Now register it as a trace exporter.
|
||||
trace.RegisterExporter(exp)
|
||||
|
||||
// Then use the OpenCensus tracing library, like we normally would.
|
||||
ctx, span := trace.StartSpan(context.Background(), "AgentExporter-Example")
|
||||
defer span.End()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
_, iSpan := trace.StartSpan(ctx, fmt.Sprintf("Sample-%d", i))
|
||||
<-time.After(6 * time.Millisecond)
|
||||
iSpan.End()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[OCAgentReadme]: https://github.com/census-instrumentation/opencensus-proto/tree/master/opencensus/proto/agent#opencensus-agent-proto
|
||||
[OpenCensusGo]: https://github.com/census-instrumentation/opencensus-go
|
||||
[godoc-image]: https://godoc.org/contrib.go.opencensus.io/exporter/ocagent?status.svg
|
||||
[godoc-url]: https://godoc.org/contrib.go.opencensus.io/exporter/ocagent
|
||||
[travis-image]: https://travis-ci.org/census-ecosystem/opencensus-go-exporter-ocagent.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/census-ecosystem/opencensus-go-exporter-ocagent
|
||||
|
||||
46
vendor/contrib.go.opencensus.io/exporter/ocagent/example_test.go
generated
vendored
46
vendor/contrib.go.opencensus.io/exporter/ocagent/example_test.go
generated
vendored
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2018, OpenCensus Authors
|
||||
//
|
||||
// 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 ocagent_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/ocagent"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
exp, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName("engine"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create the agent exporter: %v", err)
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
// Now register it as a trace exporter.
|
||||
trace.RegisterExporter(exp)
|
||||
|
||||
// Then use the OpenCensus tracing library, like we normally would.
|
||||
ctx, span := trace.StartSpan(context.Background(), "AgentExporter-Example")
|
||||
defer span.End()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
_, iSpan := trace.StartSpan(ctx, fmt.Sprintf("Sample-%d", i))
|
||||
<-time.After(6 * time.Millisecond)
|
||||
iSpan.End()
|
||||
}
|
||||
}
|
||||
9
vendor/contrib.go.opencensus.io/exporter/ocagent/go.mod
generated
vendored
9
vendor/contrib.go.opencensus.io/exporter/ocagent/go.mod
generated
vendored
|
|
@ -1,9 +0,0 @@
|
|||
module contrib.go.opencensus.io/exporter/ocagent
|
||||
|
||||
require (
|
||||
github.com/census-instrumentation/opencensus-proto v0.0.2-0.20180913191712-f303ae3f8d6a
|
||||
github.com/golang/protobuf v1.2.0
|
||||
go.opencensus.io v0.17.0
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf
|
||||
google.golang.org/grpc v1.15.0
|
||||
)
|
||||
44
vendor/contrib.go.opencensus.io/exporter/ocagent/go.sum
generated
vendored
44
vendor/contrib.go.opencensus.io/exporter/ocagent/go.sum
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/census-instrumentation/opencensus-proto v0.0.1 h1:4v5I+ax5jCmwTYVaWQacX8ZSxvUZemBX4UwBGSkDeoA=
|
||||
github.com/census-instrumentation/opencensus-proto v0.0.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.0.2-0.20180913191712-f303ae3f8d6a h1:t88pXOTS5K+pjfuhTOcul6sdC4khgqB8ukyfbe62Zxo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.0.2-0.20180913191712-f303ae3f8d6a/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
go.opencensus.io v0.17.0 h1:2Cu88MYg+1LU+WVD+NWwYhyP0kKgRlN9QjWGaX0jKTE=
|
||||
go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf h1:rjxqQmxjyqerRKEj+tZW+MCm4LgpFXu18bsEoCMgDsk=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.15.0 h1:Az/KuahOM4NAidTEuJCv/RonAA7rYsTPkqXVjr+8OOw=
|
||||
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
218
vendor/contrib.go.opencensus.io/exporter/ocagent/mock_agent_test.go
generated
vendored
218
vendor/contrib.go.opencensus.io/exporter/ocagent/mock_agent_test.go
generated
vendored
|
|
@ -1,218 +0,0 @@
|
|||
// Copyright 2018, OpenCensus Authors
|
||||
//
|
||||
// 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 ocagent_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
|
||||
agenttracepb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1"
|
||||
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
|
||||
)
|
||||
|
||||
func makeMockAgent(t *testing.T) *mockAgent {
|
||||
return &mockAgent{configsToSend: make(chan *agenttracepb.UpdatedLibraryConfig), t: t, wg: new(sync.WaitGroup)}
|
||||
}
|
||||
|
||||
type mockAgent struct {
|
||||
t *testing.T
|
||||
|
||||
spans []*tracepb.Span
|
||||
mu sync.Mutex
|
||||
wg *sync.WaitGroup
|
||||
|
||||
traceNodes []*commonpb.Node
|
||||
receivedConfigs []*agenttracepb.CurrentLibraryConfig
|
||||
|
||||
configsToSend chan *agenttracepb.UpdatedLibraryConfig
|
||||
closeConfigsToSendOnce sync.Once
|
||||
|
||||
port uint16
|
||||
stopFunc func() error
|
||||
stopOnce sync.Once
|
||||
}
|
||||
|
||||
var _ agenttracepb.TraceServiceServer = (*mockAgent)(nil)
|
||||
|
||||
func (ma *mockAgent) Config(tscs agenttracepb.TraceService_ConfigServer) error {
|
||||
ma.mu.Lock()
|
||||
ma.wg.Add(1)
|
||||
ma.mu.Unlock()
|
||||
defer func() {
|
||||
ma.mu.Lock()
|
||||
ma.wg.Done()
|
||||
ma.mu.Unlock()
|
||||
}()
|
||||
|
||||
in, err := tscs.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if in == nil || in.Node == nil {
|
||||
return fmt.Errorf("the first message must contain the node identifier")
|
||||
}
|
||||
ma.receivedConfigs = append(ma.receivedConfigs, in)
|
||||
|
||||
// Push down all the configs
|
||||
for cfg := range ma.configsToSend {
|
||||
// Push down configs
|
||||
if err := tscs.Send(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// And then get back the config sent back by the client library
|
||||
back, err := tscs.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ma.receivedConfigs = append(ma.receivedConfigs, back)
|
||||
}
|
||||
|
||||
// Just for the sake of draining any configs
|
||||
// that the client-side exporter is still sending.
|
||||
for {
|
||||
back, err := tscs.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ma.receivedConfigs = append(ma.receivedConfigs, back)
|
||||
}
|
||||
}
|
||||
|
||||
func (ma *mockAgent) Export(tses agenttracepb.TraceService_ExportServer) error {
|
||||
in, err := tses.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ma.mu.Lock()
|
||||
ma.wg.Add(1)
|
||||
ma.mu.Unlock()
|
||||
defer func() {
|
||||
ma.mu.Lock()
|
||||
ma.wg.Done()
|
||||
ma.mu.Unlock()
|
||||
}()
|
||||
|
||||
// The first trace message should contain the node identifier.
|
||||
if in == nil || in.Node == nil {
|
||||
return fmt.Errorf("the first message must contain the node identifier")
|
||||
}
|
||||
ma.traceNodes = append(ma.traceNodes, in.Node)
|
||||
|
||||
// Now that we have the node identifier, let's start receiving spans.
|
||||
for {
|
||||
req, err := tses.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ma.mu.Lock()
|
||||
ma.spans = append(ma.spans, req.Spans...)
|
||||
ma.traceNodes = append(ma.traceNodes, req.Node)
|
||||
ma.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (ma *mockAgent) transitionToReceivingClientConfigs() {
|
||||
// Since we are done sending all the configs, close the configsChannel
|
||||
// so that the state can transition to receiving all the client configs.
|
||||
ma.closeConfigsToSendOnce.Do(func() {
|
||||
close(ma.configsToSend)
|
||||
})
|
||||
}
|
||||
|
||||
var errAlreadyStopped = fmt.Errorf("already stopped")
|
||||
|
||||
func (ma *mockAgent) stop() error {
|
||||
var err = errAlreadyStopped
|
||||
ma.stopOnce.Do(func() {
|
||||
ma.transitionToReceivingClientConfigs()
|
||||
|
||||
if ma.stopFunc != nil {
|
||||
err = ma.stopFunc()
|
||||
}
|
||||
})
|
||||
// Give it sometime to shutdown.
|
||||
<-time.After(160 * time.Millisecond)
|
||||
ma.mu.Lock()
|
||||
ma.wg.Wait()
|
||||
ma.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// runMockAgent is a helper function to create a mockAgent
|
||||
func runMockAgent(t *testing.T) *mockAgent {
|
||||
return runMockAgentAtAddr(t, ":0")
|
||||
}
|
||||
|
||||
func runMockAgentAtAddr(t *testing.T, addr string) *mockAgent {
|
||||
var deferFuncs []func() error
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get an address: %v", err)
|
||||
}
|
||||
deferFuncs = append(deferFuncs, ln.Close)
|
||||
|
||||
srv := grpc.NewServer()
|
||||
ma := makeMockAgent(t)
|
||||
agenttracepb.RegisterTraceServiceServer(srv, ma)
|
||||
go func() {
|
||||
_ = srv.Serve(ln)
|
||||
}()
|
||||
|
||||
deferFunc := func() error {
|
||||
srv.Stop()
|
||||
return ln.Close()
|
||||
}
|
||||
|
||||
_, agentPortStr, _ := net.SplitHostPort(ln.Addr().String())
|
||||
agentPort, _ := strconv.Atoi(agentPortStr)
|
||||
|
||||
ma.port = uint16(agentPort)
|
||||
ma.stopFunc = deferFunc
|
||||
|
||||
return ma
|
||||
}
|
||||
|
||||
func (ma *mockAgent) getSpans() []*tracepb.Span {
|
||||
ma.mu.Lock()
|
||||
spans := append([]*tracepb.Span{}, ma.spans...)
|
||||
ma.mu.Unlock()
|
||||
|
||||
return spans
|
||||
}
|
||||
|
||||
func (ma *mockAgent) getReceivedConfigs() []*agenttracepb.CurrentLibraryConfig {
|
||||
ma.mu.Lock()
|
||||
receivedConfigs := append([]*agenttracepb.CurrentLibraryConfig{}, ma.receivedConfigs...)
|
||||
ma.mu.Unlock()
|
||||
|
||||
return receivedConfigs
|
||||
}
|
||||
|
||||
func (ma *mockAgent) getTraceNodes() []*commonpb.Node {
|
||||
ma.mu.Lock()
|
||||
traceNodes := append([]*commonpb.Node{}, ma.traceNodes...)
|
||||
ma.mu.Unlock()
|
||||
|
||||
return traceNodes
|
||||
}
|
||||
329
vendor/contrib.go.opencensus.io/exporter/ocagent/ocagent_test.go
generated
vendored
329
vendor/contrib.go.opencensus.io/exporter/ocagent/ocagent_test.go
generated
vendored
|
|
@ -1,329 +0,0 @@
|
|||
// Copyright 2018, OpenCensus Authors
|
||||
//
|
||||
// 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 ocagent_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/ocagent"
|
||||
commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
|
||||
agenttracepb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1"
|
||||
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
|
||||
"go.opencensus.io"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func TestNewExporter_endToEnd(t *testing.T) {
|
||||
ma := runMockAgent(t)
|
||||
defer ma.stop()
|
||||
|
||||
serviceName := "endToEnd_test"
|
||||
exp, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithPort(ma.port), ocagent.WithServiceName(serviceName))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a new agent exporter: %v", err)
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
// Once we've register the exporter, we can then send over a bunch of spans.
|
||||
trace.RegisterExporter(exp)
|
||||
defer trace.UnregisterExporter(exp)
|
||||
|
||||
// Let the agent push down a couple of configurations.
|
||||
// 1. Always sample
|
||||
ma.configsToSend <- &agenttracepb.UpdatedLibraryConfig{
|
||||
Config: &tracepb.TraceConfig{
|
||||
Sampler: &tracepb.TraceConfig_ConstantSampler{
|
||||
ConstantSampler: &tracepb.ConstantSampler{Decision: true}, // Always sample
|
||||
},
|
||||
},
|
||||
}
|
||||
<-time.After(5 * time.Millisecond)
|
||||
|
||||
// Now create a couple of spans
|
||||
for i := 0; i < 4; i++ {
|
||||
_, span := trace.StartSpan(context.Background(), "AlwaysSample")
|
||||
span.Annotatef([]trace.Attribute{trace.Int64Attribute("i", int64(i))}, "Annotation")
|
||||
span.End()
|
||||
}
|
||||
<-time.After(10 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
// 2. Never sample
|
||||
ma.configsToSend <- &agenttracepb.UpdatedLibraryConfig{
|
||||
Config: &tracepb.TraceConfig{
|
||||
Sampler: &tracepb.TraceConfig_ConstantSampler{
|
||||
ConstantSampler: &tracepb.ConstantSampler{Decision: false}, // Never sample
|
||||
},
|
||||
},
|
||||
}
|
||||
<-time.After(5 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
// Now create a couple of spans
|
||||
for i, n := 0, 2; i < n; i++ {
|
||||
_, span := trace.StartSpan(context.Background(), "NeverSample")
|
||||
span.Annotatef([]trace.Attribute{trace.Int64Attribute("i", int64(n-i))}, "Annotation")
|
||||
span.End()
|
||||
}
|
||||
<-time.After(10 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
// 3. Probability sampler (100%)
|
||||
ma.configsToSend <- &agenttracepb.UpdatedLibraryConfig{
|
||||
Config: &tracepb.TraceConfig{
|
||||
Sampler: &tracepb.TraceConfig_ProbabilitySampler{
|
||||
ProbabilitySampler: &tracepb.ProbabilitySampler{SamplingProbability: 1.0}, // 100% probability
|
||||
},
|
||||
},
|
||||
}
|
||||
<-time.After(5 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
// Now create a couple of spans
|
||||
for i := 0; i < 3; i++ {
|
||||
_, span := trace.StartSpan(context.Background(), "ProbabilitySampler-100%")
|
||||
span.Annotatef([]trace.Attribute{trace.BoolAttribute("odd", i&1 == 1)}, "Annotation")
|
||||
span.End()
|
||||
}
|
||||
<-time.After(10 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
// 4. Probability sampler (0%)
|
||||
ma.configsToSend <- &agenttracepb.UpdatedLibraryConfig{
|
||||
Config: &tracepb.TraceConfig{
|
||||
Sampler: &tracepb.TraceConfig_ProbabilitySampler{
|
||||
ProbabilitySampler: &tracepb.ProbabilitySampler{SamplingProbability: 0.0}, // 0% probability
|
||||
},
|
||||
},
|
||||
}
|
||||
<-time.After(5 * time.Millisecond)
|
||||
exp.Flush()
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
_, span := trace.StartSpan(context.Background(), "ProbabilitySampler-0%")
|
||||
span.Annotatef([]trace.Attribute{trace.BoolAttribute("even", i&1 == 0)}, "Annotation")
|
||||
span.End()
|
||||
}
|
||||
// Give the traces some time to be exported or dropped by the core library
|
||||
<-time.After(5 * time.Millisecond)
|
||||
|
||||
ma.transitionToReceivingClientConfigs()
|
||||
<-time.After(5 * time.Millisecond)
|
||||
|
||||
// Now invoke Flush on the exporter.
|
||||
exp.Flush()
|
||||
<-time.After(5 * time.Millisecond)
|
||||
|
||||
// Now shutdown the exporter
|
||||
if err := exp.Stop(); err != nil {
|
||||
t.Errorf("Failed to stop the exporter: %v", err)
|
||||
}
|
||||
|
||||
// Shutdown the agent too so that we can begin
|
||||
// verification checks of expected data back.
|
||||
ma.stop()
|
||||
|
||||
// Expecting 5 receivedConfigs: the first one with the nodeInfo
|
||||
// and the rest with {AlwaysSample, NeverSample, 100%, 0%}
|
||||
spans := ma.getSpans()
|
||||
traceNodes := ma.getTraceNodes()
|
||||
receivedConfigs := ma.getReceivedConfigs()
|
||||
|
||||
if g, w := len(receivedConfigs), 5; g != w {
|
||||
t.Errorf("ReceivedConfigs: got %d want %d", g, w)
|
||||
}
|
||||
|
||||
// Expecting 7 spanData that were sampled, given that
|
||||
// two of the trace configs pushed down to the client
|
||||
// were {NeverSample, ProbabilitySampler(0.0)}
|
||||
if g, w := len(spans), 7; g != w {
|
||||
t.Errorf("Spans: got %d want %d", g, w)
|
||||
}
|
||||
|
||||
// Now check that the responses received by the agent properly
|
||||
// contain the node identifier that we expect the exporter to have.
|
||||
wantIdentifier := &commonpb.ProcessIdentifier{
|
||||
HostName: os.Getenv("HOSTNAME"),
|
||||
Pid: uint32(os.Getpid()),
|
||||
}
|
||||
wantLibraryInfo := &commonpb.LibraryInfo{
|
||||
Language: commonpb.LibraryInfo_GO_LANG,
|
||||
ExporterVersion: ocagent.Version,
|
||||
CoreLibraryVersion: opencensus.Version(),
|
||||
}
|
||||
wantServiceInfo := &commonpb.ServiceInfo{
|
||||
Name: serviceName,
|
||||
}
|
||||
|
||||
var firstNodeInConfig, firstNodeInTraceExport *commonpb.Node
|
||||
if len(receivedConfigs) > 0 {
|
||||
firstNodeInConfig = receivedConfigs[0].Node
|
||||
}
|
||||
if len(traceNodes) > 0 {
|
||||
firstNodeInTraceExport = traceNodes[0]
|
||||
}
|
||||
nodeComparisons := []struct {
|
||||
name string
|
||||
node *commonpb.Node
|
||||
}{
|
||||
// Expecting the first config message that the agent got to contain the nodeInfo
|
||||
{name: "Config", node: firstNodeInConfig},
|
||||
// Expecting the first span message that the agent got to contain the nodeInfo
|
||||
{name: "Trace", node: firstNodeInTraceExport},
|
||||
}
|
||||
|
||||
for _, tt := range nodeComparisons {
|
||||
node := tt.node
|
||||
if node == nil {
|
||||
t.Errorf("%q: first message should contain a non-nil Node", tt.name)
|
||||
} else if g, w := node.Identifier, wantIdentifier; !sameProcessIdentifier(g, w) {
|
||||
t.Errorf("%q: ProcessIdentifier mismatch\nGot %#v\nWant %#v", tt.name, g, w)
|
||||
} else if g, w := node.LibraryInfo, wantLibraryInfo; !sameLibraryInfo(g, w) {
|
||||
t.Errorf("%q: LibraryInfo mismatch\nGot %#v\nWant %#v", tt.name, g, w)
|
||||
} else if g, w := node.ServiceInfo, wantServiceInfo; !sameServiceInfo(g, w) {
|
||||
t.Errorf("%q: ServiceInfo mismatch\nGot %#v\nWant %#v", tt.name, g, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewExporter_invokeStartThenStopManyTimes(t *testing.T) {
|
||||
ma := runMockAgent(t)
|
||||
defer ma.stop()
|
||||
|
||||
exp, err := ocagent.NewUnstartedExporter(ocagent.WithInsecure(), ocagent.WithPort(ma.port))
|
||||
if err != nil {
|
||||
t.Fatal("Surprisingly connected with a bad port")
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
// Invoke Start numerous times
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := exp.Start(); err != nil {
|
||||
t.Errorf("#%d unexpected Start error: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
exp.Stop()
|
||||
// Invoke Stop numerous times
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := exp.Stop(); err == nil || !strings.Contains(err.Error(), "not started") {
|
||||
t.Errorf(`#%d got error (%v) expected a "not started error"`, i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewExporter_agentConnectionDiesInMidst(t *testing.T) {
|
||||
ma := runMockAgent(t)
|
||||
exp, err := ocagent.NewUnstartedExporter(ocagent.WithInsecure(), ocagent.WithPort(ma.port))
|
||||
if err != nil {
|
||||
t.Fatal("Surprisingly connected with a bad port")
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
if err := exp.Start(); err != nil {
|
||||
t.Fatalf("Unexpected Start error: %v", err)
|
||||
}
|
||||
|
||||
// Stop the agent right away to simulate killing
|
||||
// the connection in the midst of communication.
|
||||
ma.stop()
|
||||
|
||||
exp.ExportSpan(&trace.SpanData{Name: "in the midst"})
|
||||
}
|
||||
|
||||
// This test takes a long time to run: to skip it, run tests using: -short
|
||||
func TestNewExporter_agentOnBadConnection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skipf("Skipping this long running test")
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to grab an available port: %v", err)
|
||||
}
|
||||
// Firstly close the "agent's" channel: optimistically this address won't get reused ASAP
|
||||
// However, our goal of closing it is to simulate an unavailable connection
|
||||
ln.Close()
|
||||
|
||||
startTime := time.Now()
|
||||
// If this returns in less than 6.5s report an error
|
||||
// since that's a sign that exponential backoff didn't happen.
|
||||
wantMinDuration := (6 * time.Second) + (500 * time.Millisecond)
|
||||
defer func() {
|
||||
timeSpent := time.Now().Sub(startTime)
|
||||
if timeSpent < wantMinDuration {
|
||||
t.Errorf("Took %s, yet with a non-existent connection it should take at least %s",
|
||||
timeSpent, wantMinDuration)
|
||||
}
|
||||
}()
|
||||
|
||||
_, agentPortStr, _ := net.SplitHostPort(ln.Addr().String())
|
||||
agentPort, _ := strconv.Atoi(agentPortStr)
|
||||
|
||||
exp, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithPort(uint16(agentPort)))
|
||||
if err == nil {
|
||||
t.Fatal("Surprisingly connected to an unavailable non-gRPC connection")
|
||||
}
|
||||
if exp != nil {
|
||||
t.Fatalf("Surprisingly created an exporter: %#v", exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewExporter_withAddress(t *testing.T) {
|
||||
ma := runMockAgent(t)
|
||||
defer ma.stop()
|
||||
|
||||
addr := fmt.Sprintf("localhost:%d", ma.port)
|
||||
exp, err := ocagent.NewUnstartedExporter(ocagent.WithInsecure(), ocagent.WithAddress(addr))
|
||||
if err != nil {
|
||||
t.Fatal("Surprisingly connected with a bad port")
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
if err := exp.Start(); err != nil {
|
||||
t.Fatalf("Unexpected Start error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Best case comparison for information that we can externally introspect
|
||||
func sameProcessIdentifier(n1, n2 *commonpb.ProcessIdentifier) bool {
|
||||
if n1 == nil || n2 == nil {
|
||||
return n1 == n2
|
||||
}
|
||||
return n1.HostName == n2.HostName && n1.Pid == n2.Pid
|
||||
}
|
||||
|
||||
func sameLibraryInfo(li1, li2 *commonpb.LibraryInfo) bool {
|
||||
if li1 == nil || li2 == nil {
|
||||
return li1 == li2
|
||||
}
|
||||
return li1.Language == li2.Language &&
|
||||
li1.ExporterVersion == li2.ExporterVersion &&
|
||||
li1.CoreLibraryVersion == li2.CoreLibraryVersion
|
||||
}
|
||||
|
||||
func sameServiceInfo(si1, si2 *commonpb.ServiceInfo) bool {
|
||||
if si1 == nil || si2 == nil {
|
||||
return si1 == si2
|
||||
}
|
||||
return si1.Name == si2.Name
|
||||
}
|
||||
166
vendor/contrib.go.opencensus.io/exporter/ocagent/transform_spans_test.go
generated
vendored
166
vendor/contrib.go.opencensus.io/exporter/ocagent/transform_spans_test.go
generated
vendored
|
|
@ -1,166 +0,0 @@
|
|||
// Copyright 2018, OpenCensus Authors
|
||||
//
|
||||
// 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 ocagent_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/ocagent"
|
||||
"go.opencensus.io/trace"
|
||||
"go.opencensus.io/trace/tracestate"
|
||||
|
||||
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
)
|
||||
|
||||
func TestOCSpanToProtoSpan_endToEnd(t *testing.T) {
|
||||
// The goal of this test is to ensure that each
|
||||
// spanData is transformed and exported correctly!
|
||||
|
||||
agent := runMockAgent(t)
|
||||
defer agent.stop()
|
||||
|
||||
serviceName := "spanTranslation"
|
||||
exp, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithPort(agent.port), ocagent.WithServiceName(serviceName))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a new agent exporter: %v", err)
|
||||
}
|
||||
defer exp.Stop()
|
||||
|
||||
startTime := time.Now()
|
||||
endTime := startTime.Add(10 * time.Second)
|
||||
ocTracestate, err := tracestate.New(new(tracestate.Tracestate), tracestate.Entry{Key: "foo", Value: "bar"},
|
||||
tracestate.Entry{Key: "a", Value: "b"})
|
||||
if err != nil || ocTracestate == nil {
|
||||
t.Fatalf("Failed to create ocTracestate: %v", err)
|
||||
}
|
||||
|
||||
ocSpanData := &trace.SpanData{
|
||||
SpanContext: trace.SpanContext{
|
||||
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
|
||||
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
|
||||
Tracestate: ocTracestate,
|
||||
},
|
||||
SpanKind: trace.SpanKindServer,
|
||||
ParentSpanID: trace.SpanID{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
|
||||
Name: "End-To-End Here",
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
MessageEvents: []trace.MessageEvent{
|
||||
{Time: startTime, EventType: trace.MessageEventTypeSent, UncompressedByteSize: 1024, CompressedByteSize: 512},
|
||||
{Time: endTime, EventType: trace.MessageEventTypeRecv, UncompressedByteSize: 1024, CompressedByteSize: 1000},
|
||||
},
|
||||
Links: []trace.Link{
|
||||
{
|
||||
TraceID: trace.TraceID{0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF},
|
||||
SpanID: trace.SpanID{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
|
||||
Type: trace.LinkTypeParent,
|
||||
},
|
||||
{
|
||||
TraceID: trace.TraceID{0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF},
|
||||
SpanID: trace.SpanID{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7},
|
||||
Type: trace.LinkTypeChild,
|
||||
},
|
||||
},
|
||||
Status: trace.Status{
|
||||
Code: trace.StatusCodeInternal,
|
||||
Message: "This is not a drill!",
|
||||
},
|
||||
HasRemoteParent: true,
|
||||
Attributes: map[string]interface{}{
|
||||
"timeout_ns": int64(12e9),
|
||||
"agent": "ocagent",
|
||||
"cache_hit": true,
|
||||
"ping_count": int(25), // Should be transformed into int64
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: file a bug with opencensus-go because trace.Annotation.Attributes' type is map[string]interface{}
|
||||
// yet Attribute value and key cannot be easily introspected, so we can't easily test the values.
|
||||
|
||||
exp.ExportSpan(ocSpanData)
|
||||
// Also try to export a nil span and it should never make it
|
||||
exp.ExportSpan(nil)
|
||||
exp.Flush()
|
||||
<-time.After(100 * time.Millisecond)
|
||||
exp.Stop()
|
||||
agent.stop()
|
||||
|
||||
spans := agent.getSpans()
|
||||
if len(spans) == 0 || spans[0] == nil {
|
||||
t.Fatal("Expected the exported span")
|
||||
}
|
||||
|
||||
wantProtoSpan := &tracepb.Span{
|
||||
TraceId: []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
|
||||
SpanId: []byte{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
|
||||
ParentSpanId: []byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
|
||||
Name: &tracepb.TruncatableString{Value: "End-To-End Here"},
|
||||
Kind: tracepb.Span_SERVER,
|
||||
StartTime: timeToTimestamp(startTime),
|
||||
EndTime: timeToTimestamp(endTime),
|
||||
Status: &tracepb.Status{
|
||||
Code: 13,
|
||||
Message: "This is not a drill!",
|
||||
},
|
||||
Links: &tracepb.Span_Links{
|
||||
Link: []*tracepb.Span_Link{
|
||||
{
|
||||
TraceId: []byte{0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF},
|
||||
SpanId: []byte{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
|
||||
Type: tracepb.Span_Link_PARENT_LINKED_SPAN,
|
||||
},
|
||||
{
|
||||
TraceId: []byte{0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF},
|
||||
SpanId: []byte{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7},
|
||||
Type: tracepb.Span_Link_CHILD_LINKED_SPAN,
|
||||
},
|
||||
},
|
||||
},
|
||||
Tracestate: &tracepb.Span_Tracestate{
|
||||
Entries: []*tracepb.Span_Tracestate_Entry{
|
||||
{Key: "foo", Value: "bar"},
|
||||
{Key: "a", Value: "b"},
|
||||
},
|
||||
},
|
||||
Attributes: &tracepb.Span_Attributes{
|
||||
AttributeMap: map[string]*tracepb.AttributeValue{
|
||||
"cache_hit": {Value: &tracepb.AttributeValue_BoolValue{BoolValue: true}},
|
||||
"timeout_ns": {Value: &tracepb.AttributeValue_IntValue{IntValue: 12e9}},
|
||||
"ping_count": {Value: &tracepb.AttributeValue_IntValue{IntValue: 25}},
|
||||
"agent": {Value: &tracepb.AttributeValue_StringValue{
|
||||
StringValue: &tracepb.TruncatableString{Value: "ocagent"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if g, w := spans[0], wantProtoSpan; !reflect.DeepEqual(g, w) {
|
||||
for i := 0; i < len(w.Links.Link); i++ {
|
||||
t.Logf("#%d:: \nGot: %#v\nWant: %#v\n\n", i, g.Links.Link[i], w.Links.Link[i])
|
||||
}
|
||||
t.Fatalf("End-to-end transformed span\n\tGot %+v\n\tWant %+v", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
func timeToTimestamp(t time.Time) *timestamp.Timestamp {
|
||||
nanoTime := t.UnixNano()
|
||||
return ×tamp.Timestamp{
|
||||
Seconds: nanoTime / 1e9,
|
||||
Nanos: int32(nanoTime % 1e9),
|
||||
}
|
||||
}
|
||||
1337
vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md
generated
vendored
1337
vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md
generated
vendored
File diff suppressed because it is too large
Load diff
12
vendor/github.com/Azure/azure-sdk-for-go/CODEOWNERS
generated
vendored
12
vendor/github.com/Azure/azure-sdk-for-go/CODEOWNERS
generated
vendored
|
|
@ -1,12 +0,0 @@
|
|||
/documentation/ @joshgav
|
||||
/profiles/ @jhendrixMSFT @vladbarosan
|
||||
/services/ @jhendrixMSFT @vladbarosan
|
||||
/storage/ @jhendrixMSFT @vladbarosan
|
||||
/tools/apidiff/ @jhendrixMSFT @vladbarosan
|
||||
/tools/generator/ @jhendrixMSFT @vladbarosan
|
||||
/tools/indexer/ @jhendrixMSFT @vladbarosan
|
||||
/tools/profileBuilder/ @jhendrixMSFT @vladbarosan
|
||||
/version/ @jhendrixMSFT @vladbarosan
|
||||
.travis.yml @jhendrixMSFT @vladbarosan
|
||||
doc.go @joshgav
|
||||
findTestedPackages.sh @jhendrixMSFT @vladbarosan
|
||||
17
vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md
generated
vendored
17
vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md
generated
vendored
|
|
@ -1,17 +0,0 @@
|
|||
# Contributing
|
||||
|
||||
As of version 14, the Azure SDK for Go is GA. We maintain only a `master` branch for releases and a `latest` branch for the latest changes.
|
||||
|
||||
For bugs or feature requests you can submit them using the [Github issues page][issues] and filling the appropriate template.
|
||||
|
||||
For Pull Requests, please submit them _ONLY_ to `latest` branch.
|
||||
|
||||
Also please see these [guidelines][] about contributing to Azure projects.
|
||||
|
||||
This project follows the [Microsoft Open Source Code of Conduct][coc]. For more information see the [Code of Conduct FAQ][cocfaq]. Contact [opencode@microsoft.com][cocmail] with questions and comments.
|
||||
|
||||
[guidelines]: http://azure.github.io/guidelines/
|
||||
[coc]: https://opensource.microsoft.com/codeofconduct/
|
||||
[cocfaq]: https://opensource.microsoft.com/codeofconduct/faq/
|
||||
[cocmail]: mailto:opencode@microsoft.com
|
||||
[issues]: https://github.com/Azure/Azure-sdk-for-go/issues
|
||||
384
vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock
generated
vendored
384
vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock
generated
vendored
|
|
@ -1,384 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e1b859e3d9e90007d5fbf25edf57733b224f1857f6592636130afab3af8cfae7"
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:597d79297997cdf9f13427b0644558c6b845451607a6893c9b00b3625ab1f4f3"
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = [
|
||||
"autorest",
|
||||
"autorest/adal",
|
||||
"autorest/azure",
|
||||
"autorest/azure/auth",
|
||||
"autorest/azure/cli",
|
||||
"autorest/date",
|
||||
"autorest/to",
|
||||
"autorest/validation",
|
||||
"logger",
|
||||
"tracing",
|
||||
"version",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "528b76fd0ebec0682f3e3da7c808cd472b999615"
|
||||
version = "v11.2.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e0a4505d5cf7ac6b5d92e3aee79d838b5f1ae8e9641ec7fa5d1e9b01d7a7ea95"
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = [
|
||||
"gen-go/agent/common/v1",
|
||||
"gen-go/agent/trace/v1",
|
||||
"gen-go/trace/v1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "24333298e36590ea0716598caacc8959fc393c48"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6098222470fe0172157ce9bbef5d2200df4edde17ee649c5d6e48330e4afa4c6"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7f175a633086a933d1940a7e7dc2154a0070a7c25fb4a2f671f3eef1a34d1fd7"
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5448fe645cb1964ba70ac8f9f2ffe975e61a536c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5ee2023eac9f57de6bdb055625e8ac014b2c2b39e22bb88721d62a033de76bd1"
|
||||
name = "github.com/dnaeon/go-vcr"
|
||||
packages = [
|
||||
"cassette",
|
||||
"recorder",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "5637cf3d8a31b20882d79bd0e53a186d3821b155"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e9ffb9315dce0051beb757d0f0fc25db57c4da654efc4eada4ea109c2d9da815"
|
||||
name = "github.com/globalsign/mgo"
|
||||
packages = [
|
||||
".",
|
||||
"bson",
|
||||
"internal/json",
|
||||
"internal/sasl",
|
||||
"internal/scram",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "eeefdecb41b842af6dc652aaea4026e8403e62df"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3108ec0946181c60040ff51b811908f89d03e521e2b4ade5ef5c65b3c0e911ae"
|
||||
name = "github.com/kr/pretty"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "73f6ac0b30a98e433b289500d779f50c1a6f0712"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:11b056b4421396ab14e384ab8ab8c2079b03f1e51aa5eb4d9b81f9e0d1aa8fbf"
|
||||
name = "github.com/kr/text"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a69ca302e0e9bab6743b40cb720ef02a8abcc2072eb55c0fd8869b3b285be425"
|
||||
name = "github.com/marstr/collection"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "43f1d00df9bf332cbf8d26c3eecd6c348e92f7b3"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f95025d583786875a71183888acc9d0987fc96f12d4f5afab3d7558797ea1c5a"
|
||||
name = "github.com/marstr/guid"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "8bd9a64bf37eb297b492a4101fb28e80ac0b290f"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7f569d906bdd20d906b606415b7d794f798f91a62fcfb6a4daa6d50690fb7a3f"
|
||||
name = "github.com/satori/go.uuid"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:615c827f6a892973a587c754ae5fad7acfc4352657aff23d0238fe0ba2a154df"
|
||||
name = "github.com/shopspring/decimal"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "cd690d0c9e2447b1ef2a129a6b7b49077da89b8e"
|
||||
version = "1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cbaf13cdbfef0e4734ed8a7504f57fe893d471d62a35b982bf6fb3f036449a66"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ad67dfd3799a2c58f6c65871dd141d8b53f61f600aec48ce8d7fa16a4d5476f8"
|
||||
name = "go.opencensus.io"
|
||||
packages = [
|
||||
".",
|
||||
"exemplar",
|
||||
"internal",
|
||||
"internal/tagencoding",
|
||||
"plugin/ochttp",
|
||||
"plugin/ochttp/propagation/b3",
|
||||
"plugin/ochttp/propagation/tracecontext",
|
||||
"stats",
|
||||
"stats/internal",
|
||||
"stats/view",
|
||||
"tag",
|
||||
"trace",
|
||||
"trace/internal",
|
||||
"trace/propagation",
|
||||
"trace/tracestate",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0049ee593cea6375d6bbabe5e0a30aa05576846025811df879e9fcf1223d29a2"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"pkcs12",
|
||||
"pkcs12/internal/rc2",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "b078efbc8099b041569edb8c6ab625cd430e3fce"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:41055845ee2a3f0b0fbf94f12b7a6c5322ae66c166d192e38156e0d63a6e2993"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "c44066c5c816ec500d459a2a324a753f78531ae0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2667800887f4161b5b1f49d3065204a82f974d1b857c00d7e450a5167477071f"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = ""
|
||||
revision = "d69651ed3497faee15a5363a89578e9991f6d5e2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a5c40d520f13a38fe3dbe1691f82b124dd2cdfccdbde32cfc8ea4547ae55cbc1"
|
||||
name = "golang.org/x/tools"
|
||||
packages = [
|
||||
"go/ast/astutil",
|
||||
"imports",
|
||||
"internal/fastwalk",
|
||||
"internal/gopathwalk",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2d2de6298155751e44170d1c9a9baacb688d2606"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ba7c9eafe35679d6be0b1d064ab6b841fe968496c8a8381ddb55cb192b70c996"
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
pruneopts = ""
|
||||
revision = "aff2d7231e3cd0219626182c997296a559b5a27b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5bc459e4630e2f2adcd04005a06d6f9cdf614c6ffa751309497096efcab79150"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = ""
|
||||
revision = "b69ba1387ce2108ac9bc8e8e5e5a46e7d5c72313"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1293087271e314cfa2b3decededba2ecba0ff327e7b7809e00f73f616449191c"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2e463a05d100327ca47ac218281906921038fd95"
|
||||
version = "v1.16.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v1"
|
||||
digest = "1:1d01f96bc2293b56c3dec797b8f976d7613fb30ce92bfbc994130404f7f7f031"
|
||||
name = "gopkg.in/check.v1"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "788fd78401277ebd861206a03c884797c6ec5541"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/Azure/go-autorest/autorest",
|
||||
"github.com/Azure/go-autorest/autorest/adal",
|
||||
"github.com/Azure/go-autorest/autorest/azure",
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth",
|
||||
"github.com/Azure/go-autorest/autorest/date",
|
||||
"github.com/Azure/go-autorest/autorest/to",
|
||||
"github.com/Azure/go-autorest/autorest/validation",
|
||||
"github.com/Azure/go-autorest/tracing",
|
||||
"github.com/dnaeon/go-vcr/cassette",
|
||||
"github.com/dnaeon/go-vcr/recorder",
|
||||
"github.com/globalsign/mgo",
|
||||
"github.com/marstr/collection",
|
||||
"github.com/marstr/guid",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/satori/go.uuid",
|
||||
"github.com/shopspring/decimal",
|
||||
"github.com/spf13/cobra",
|
||||
"golang.org/x/crypto/pkcs12",
|
||||
"golang.org/x/tools/imports",
|
||||
"gopkg.in/check.v1",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
61
vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml
generated
vendored
61
vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml
generated
vendored
|
|
@ -1,61 +0,0 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
version = "11.2.7"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/dnaeon/go-vcr"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/globalsign/mgo"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/marstr/collection"
|
||||
version = "1.0.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/marstr/guid"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/satori/go.uuid"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/shopspring/decimal"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
|
||||
[[constraint]]
|
||||
branch = "v1"
|
||||
name = "gopkg.in/check.v1"
|
||||
505
vendor/github.com/Azure/azure-sdk-for-go/README.md
generated
vendored
505
vendor/github.com/Azure/azure-sdk-for-go/README.md
generated
vendored
|
|
@ -1,505 +0,0 @@
|
|||
# Azure SDK for Go
|
||||
|
||||
[](https://godoc.org/github.com/Azure/azure-sdk-for-go)
|
||||
|
||||
[](https://travis-ci.org/Azure/azure-sdk-for-go)
|
||||
|
||||
[](https://goreportcard.com/report/github.com/Azure/azure-sdk-for-go)
|
||||
|
||||
azure-sdk-for-go provides Go packages for managing and using Azure services.
|
||||
It is continuously tested with Go 1.8, 1.9, 1.10, 1.11 and master.
|
||||
|
||||
To be notified about updates and changes, subscribe to the [Azure update
|
||||
feed](https://azure.microsoft.com/updates/).
|
||||
|
||||
Users may prefer to jump right in to our samples repo at
|
||||
[github.com/Azure-Samples/azure-sdk-for-go-samples][samples_repo].
|
||||
|
||||
Questions and feedback? Chat with us in the **[#Azure SDK
|
||||
channel](https://gophers.slack.com/messages/CA7HK8EEP)** on the [Gophers
|
||||
Slack](https://gophers.slack.com/). Sign up
|
||||
[here](https://invite.slack.golangbridge.org) first if necessary.
|
||||
|
||||
|
||||
## Package Updates
|
||||
|
||||
Most packages in the SDK are generated from [Azure API specs][azure_rest_specs]
|
||||
using [Azure/autorest.go][] and [Azure/autorest][]. These generated packages
|
||||
depend on the HTTP client implemented at [Azure/go-autorest][].
|
||||
|
||||
[azure_rest_specs]: https://github.com/Azure/azure-rest-api-specs
|
||||
[azure/autorest]: https://github.com/Azure/autorest
|
||||
[azure/autorest.go]: https://github.com/Azure/autorest.go
|
||||
[azure/go-autorest]: https://github.com/Azure/go-autorest
|
||||
|
||||
The SDK codebase adheres to [semantic versioning](https://semver.org) and thus
|
||||
avoids breaking changes other than at major (x.0.0) releases. Because Azure's
|
||||
APIs are updated frequently, we release a **new major version at the end of
|
||||
each month** with a full changelog. For more details and background see [SDK Update
|
||||
Practices](https://github.com/Azure/azure-sdk-for-go/wiki/SDK-Update-Practices).
|
||||
|
||||
To more reliably manage dependencies like the Azure SDK in your applications we
|
||||
recommend [golang/dep](https://github.com/golang/dep).
|
||||
|
||||
Packages that are still in public preview can be found under the ./services/preview
|
||||
directory. Please be aware that since these packages are in preview they are subject
|
||||
to change, including breaking changes outside of a major semver bump.
|
||||
|
||||
## Other Azure Go Packages
|
||||
|
||||
Azure provides several other packages for using services from Go, listed below.
|
||||
If a package you need isn't available please open an issue and let us know.
|
||||
|
||||
| Service | Import Path/Repo |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| Storage - Blobs | [github.com/Azure/azure-storage-blob-go](https://github.com/Azure/azure-storage-blob-go) |
|
||||
| Storage - Files | [github.com/Azure/azure-storage-file-go](https://github.com/Azure/azure-storage-file-go) |
|
||||
| Storage - Queues | [github.com/Azure/azure-storage-queue-go](https://github.com/Azure/azure-storage-queue-go) |
|
||||
| Service Bus | [github.com/Azure/azure-service-bus-go](https://github.com/Azure/azure-service-bus-go) |
|
||||
| Event Hubs | [github.com/Azure/azure-event-hubs-go](https://github.com/Azure/azure-event-hubs-go) |
|
||||
| Application Insights | [github.com/Microsoft/ApplicationInsights-go](https://github.com/Microsoft/ApplicationInsights-go) |
|
||||
|
||||
# Install and Use:
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/Azure/azure-sdk-for-go/...
|
||||
```
|
||||
|
||||
or if you use dep, within your repo run:
|
||||
|
||||
```sh
|
||||
$ dep ensure -add github.com/Azure/azure-sdk-for-go
|
||||
```
|
||||
|
||||
If you need to install Go, follow [the official instructions](https://golang.org/dl/).
|
||||
|
||||
## Use
|
||||
|
||||
For many more scenarios and examples see
|
||||
[Azure-Samples/azure-sdk-for-go-samples][samples_repo].
|
||||
|
||||
Apply the following general steps to use packages in this repo. For more on
|
||||
authentication and the `Authorizer` interface see [the next
|
||||
section](#authentication).
|
||||
|
||||
1. Import a package from the [services][services_dir] directory.
|
||||
2. Create and authenticate a client with a `New*Client` func, e.g.
|
||||
`c := compute.NewVirtualMachinesClient(...)`.
|
||||
3. Invoke API methods using the client, e.g.
|
||||
`res, err := c.CreateOrUpdate(...)`.
|
||||
4. Handle responses and errors.
|
||||
|
||||
[services_dir]: https://github.com/Azure/azure-sdk-for-go/tree/master/services
|
||||
|
||||
For example, to create a new virtual network (substitute your own values for
|
||||
strings in angle brackets):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// create a VirtualNetworks client
|
||||
vnetClient := network.NewVirtualNetworksClient("<subscriptionID>")
|
||||
|
||||
// create an authorizer from env vars or Azure Managed Service Idenity
|
||||
authorizer, err := auth.NewAuthorizerFromEnvironment()
|
||||
if err == nil {
|
||||
vnetClient.Authorizer = authorizer
|
||||
}
|
||||
|
||||
// call the VirtualNetworks CreateOrUpdate API
|
||||
vnetClient.CreateOrUpdate(context.Background(),
|
||||
"<resourceGroupName>",
|
||||
"<vnetName>",
|
||||
network.VirtualNetwork{
|
||||
Location: to.StringPtr("<azureRegion>"),
|
||||
VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{
|
||||
AddressSpace: &network.AddressSpace{
|
||||
AddressPrefixes: &[]string{"10.0.0.0/8"},
|
||||
},
|
||||
Subnets: &[]network.Subnet{
|
||||
{
|
||||
Name: to.StringPtr("<subnet1Name>"),
|
||||
SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
|
||||
AddressPrefix: to.StringPtr("10.0.0.0/16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: to.StringPtr("<subnet2Name>"),
|
||||
SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
|
||||
AddressPrefix: to.StringPtr("10.1.0.0/16"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
Typical SDK operations must be authenticated and authorized. The _Authorizer_
|
||||
interface allows use of any auth style in requests, such as inserting an OAuth2
|
||||
Authorization header and bearer token received from Azure AD.
|
||||
|
||||
The SDK itself provides a simple way to get an authorizer which first checks
|
||||
for OAuth client credentials in environment variables and then falls back to
|
||||
Azure's [Managed Service Identity]() when available, e.g. when on an Azure
|
||||
VM. The following snippet from [the previous section](#use) demonstrates
|
||||
this helper.
|
||||
|
||||
```go
|
||||
import github.com/Azure/go-autorest/autorest/azure/auth
|
||||
|
||||
// create a VirtualNetworks client
|
||||
vnetClient := network.NewVirtualNetworksClient("<subscriptionID>")
|
||||
|
||||
// create an authorizer from env vars or Azure Managed Service Idenity
|
||||
authorizer, err := auth.NewAuthorizerFromEnvironment()
|
||||
if err == nil {
|
||||
vnetClient.Authorizer = authorizer
|
||||
}
|
||||
|
||||
// call the VirtualNetworks CreateOrUpdate API
|
||||
vnetClient.CreateOrUpdate(context.Background(),
|
||||
// ...
|
||||
```
|
||||
|
||||
The following environment variables help determine authentication configuration:
|
||||
|
||||
- `AZURE_ENVIRONMENT`: Specifies the Azure Environment to use. If not set, it
|
||||
defaults to `AzurePublicCloud`. Not applicable to authentication with Managed
|
||||
Service Identity (MSI).
|
||||
- `AZURE_AD_RESOURCE`: Specifies the AAD resource ID to use. If not set, it
|
||||
defaults to `ResourceManagerEndpoint` for operations with Azure Resource
|
||||
Manager. You can also choose an alternate resource programatically with
|
||||
`auth.NewAuthorizerFromEnvironmentWithResource(resource string)`.
|
||||
|
||||
### More Authentication Details
|
||||
|
||||
The previous is the first and most recommended of several authentication
|
||||
options offered by the SDK because it allows seamless use of both service
|
||||
principals and [Azure Managed Service Identity][]. Other options are listed
|
||||
below.
|
||||
|
||||
> Note: If you need to create a new service principal, run `az ad sp create-for-rbac -n "<app_name>"` in the
|
||||
> [azure-cli](https://github.com/Azure/azure-cli). See [these
|
||||
> docs](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest)
|
||||
> for more info. Copy the new principal's ID, secret, and tenant ID for use in
|
||||
> your app, or consider the `--sdk-auth` parameter for serialized output.
|
||||
|
||||
[azure managed service identity]: https://docs.microsoft.com/en-us/azure/active-directory/msi-overview
|
||||
|
||||
- The `auth.NewAuthorizerFromEnvironment()` described above creates an authorizer
|
||||
from the first available of the following configuration:
|
||||
|
||||
1. **Client Credentials**: Azure AD Application ID and Secret.
|
||||
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_CLIENT_SECRET`: Specifies the app secret to use.
|
||||
|
||||
2. **Client Certificate**: Azure AD Application ID and X.509 Certificate.
|
||||
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_CERTIFICATE_PATH`: Specifies the certificate Path to use.
|
||||
- `AZURE_CERTIFICATE_PASSWORD`: Specifies the certificate password to use.
|
||||
|
||||
3. **Resource Owner Password**: Azure AD User and Password. This grant type is *not
|
||||
recommended*, use device login instead if you need interactive login.
|
||||
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_USERNAME`: Specifies the username to use.
|
||||
- `AZURE_PASSWORD`: Specifies the password to use.
|
||||
|
||||
4. **Azure Managed Service Identity**: Delegate credential management to the
|
||||
platform. Requires that code is running in Azure, e.g. on a VM. All
|
||||
configuration is handled by Azure. See [Azure Managed Service
|
||||
Identity](https://docs.microsoft.com/en-us/azure/active-directory/msi-overview)
|
||||
for more details.
|
||||
|
||||
- The `auth.NewAuthorizerFromFile()` method creates an authorizer using
|
||||
credentials from an auth file created by the [Azure CLI][]. Follow these
|
||||
steps to utilize:
|
||||
|
||||
1. Create a service principal and output an auth file using `az ad sp create-for-rbac --sdk-auth > client_credentials.json`.
|
||||
2. Set environment variable `AZURE_AUTH_LOCATION` to the path of the saved
|
||||
output file.
|
||||
3. Use the authorizer returned by `auth.NewAuthorizerFromFile()` in your
|
||||
client as described above.
|
||||
|
||||
- The `auth.NewAuthorizerFromCLI()` method creates an authorizer which
|
||||
uses [Azure CLI][] to obtain its credentials. To use this method follow
|
||||
these steps:
|
||||
|
||||
1. Install [Azure CLI v2.0.12](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) or later. Upgrade earlier versions.
|
||||
2. Use `az login` to sign in to Azure.
|
||||
|
||||
If you receive an error, use `az account get-access-token` to verify access.
|
||||
|
||||
If Azure CLI is not installed to the default directory, you may receive an error
|
||||
reporting that `az` cannot be found.
|
||||
Use the `AzureCLIPath` environment variable to define the Azure CLI installation folder.
|
||||
|
||||
If you are signed in to Azure CLI using multiple accounts or your account has
|
||||
access to multiple subscriptions, you need to specify the specific subscription
|
||||
to be used. To do so, use:
|
||||
|
||||
```
|
||||
az account set --subscription <subscription-id>
|
||||
```
|
||||
|
||||
To verify the current account settings, use:
|
||||
|
||||
```
|
||||
az account list
|
||||
```
|
||||
|
||||
[azure cli]: https://github.com/Azure/azure-cli
|
||||
|
||||
- Finally, you can use OAuth's [Device Flow][] by calling
|
||||
`auth.NewDeviceFlowConfig()` and extracting the Authorizer as follows:
|
||||
|
||||
```go
|
||||
config := auth.NewDeviceFlowConfig(clientID, tenantID)
|
||||
a, err = config.Authorizer()
|
||||
```
|
||||
|
||||
[device flow]: https://oauth.net/2/device-flow/
|
||||
|
||||
# Versioning
|
||||
|
||||
azure-sdk-for-go provides at least a basic Go binding for every Azure API. To
|
||||
provide maximum flexibility to users, the SDK even includes previous versions of
|
||||
Azure APIs which are still in use. This enables us to support users of the
|
||||
most updated Azure datacenters, regional datacenters with earlier APIs, and
|
||||
even on-premises installations of Azure Stack.
|
||||
|
||||
**SDK versions** apply globally and are tracked by git
|
||||
[tags](https://github.com/Azure/azure-sdk-for-go/tags). These are in x.y.z form
|
||||
and generally adhere to [semantic versioning](https://semver.org) specifications.
|
||||
|
||||
**Service API versions** are generally represented by a date string and are
|
||||
tracked by offering separate packages for each version. For example, to choose the
|
||||
latest API versions for Compute and Network, use the following imports:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-12-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network"
|
||||
)
|
||||
```
|
||||
|
||||
Occasionally service-side changes require major changes to existing versions.
|
||||
These cases are noted in the changelog, and for this reason `Service API versions`
|
||||
cannot be used alone to ensure backwards compatibility.
|
||||
|
||||
All available services and versions are listed under the `services/` path in
|
||||
this repo and in [GoDoc][services_godoc]. Run `find ./services -type d -mindepth 3` to list all available service packages.
|
||||
|
||||
[services_godoc]: https://godoc.org/github.com/Azure/azure-sdk-for-go/services
|
||||
|
||||
### Profiles
|
||||
|
||||
Azure **API profiles** specify subsets of Azure APIs and versions. Profiles can provide:
|
||||
|
||||
- **stability** for your application by locking to specific API versions; and/or
|
||||
- **compatibility** for your application with Azure Stack and regional Azure datacenters.
|
||||
|
||||
In the Go SDK, profiles are available under the `profiles/` path and their
|
||||
component API versions are aliases to the true service package under
|
||||
`services/`. You can use them as follows:
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/compute/mgmt/compute"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/network/mgmt/network"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage"
|
||||
```
|
||||
|
||||
The following profiles are available for hybrid Azure and Azure Stack environments.
|
||||
- 2017-03-09
|
||||
- 2018-03-01
|
||||
|
||||
In addition to versioned profiles, we also provide two special profiles
|
||||
`latest` and `preview`. The `latest` profile contains the latest API version
|
||||
of each service, excluding any preview versions and/or content. The `preview`
|
||||
profile is similar to the `latest` profile but includes preview API versions.
|
||||
|
||||
The `latest` and `preview` profiles can help you stay up to date with API
|
||||
updates as you build applications. Since they are by definition not stable,
|
||||
however, they **should not** be used in production apps. Instead, choose the
|
||||
latest specific API version (or an older one if necessary) from the `services/`
|
||||
path.
|
||||
|
||||
As an example, to automatically use the most recent Compute APIs, use one of
|
||||
the following imports:
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/preview/compute/mgmt/compute"
|
||||
```
|
||||
|
||||
### Avoiding Breaking Changes
|
||||
|
||||
To avoid breaking changes, when specifying imports you should specify a `Service API Version` or `Profile`, as well as lock (using [dep](https://github.com/golang/dep) and soon with [Go Modules](https://github.com/golang/go/wiki/Modules)) to a specific SDK version.
|
||||
|
||||
For example, in your source code imports, use a `Service API Version` (`2017-12-01`):
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-12-01/compute"
|
||||
```
|
||||
|
||||
or `Profile` version (`2017-03-09`):
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/compute/mgmt/compute"
|
||||
```
|
||||
|
||||
As well as, for dep, a `Gopkg.toml` file with:
|
||||
|
||||
```toml
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/azure-sdk-for-go"
|
||||
version = "21.0.0"
|
||||
```
|
||||
|
||||
Combined, these techniques will ensure that breaking changes should not occur. If you are extra sensitive to changes, adding an additional [version pin](https://golang.github.io/dep/docs/Gopkg.toml.html#version-rules) in your SDK Version should satisfy your needs:
|
||||
|
||||
```toml
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/azure-sdk-for-go"
|
||||
version = "=21.3.0"
|
||||
```
|
||||
|
||||
## Inspecting and Debugging
|
||||
|
||||
### Built-in Basic Request/Response Logging
|
||||
|
||||
Starting with `go-autorest v10.15.0` you can enable basic logging of requests and responses through setting environment variables.
|
||||
Setting `AZURE_GO_SDK_LOG_LEVEL` to `LogInfo` will log request/response without their bodies. To include the bodies set the log level to `LogDebug`.
|
||||
|
||||
By default the logger writes to strerr, however it can also write to stdout or a file
|
||||
if specified in `AZURE_GO_SDK_LOG_FILE`. Note that if the specified file already exists it will be truncated.
|
||||
|
||||
**IMPORTANT:** by default the logger will redact the Authorization and Ocp-Apim-Subscription-Key
|
||||
headers. Any other secrets will _not_ be redacted.
|
||||
|
||||
### Writing Custom Request/Response Inspectors
|
||||
|
||||
All clients implement some handy hooks to help inspect the underlying requests being made to Azure.
|
||||
|
||||
- `RequestInspector`: View and manipulate the go `http.Request` before it's sent
|
||||
- `ResponseInspector`: View the `http.Response` received
|
||||
|
||||
Here is an example of how these can be used with `net/http/httputil` to see requests and responses.
|
||||
|
||||
```go
|
||||
vnetClient := network.NewVirtualNetworksClient("<subscriptionID>")
|
||||
vnetClient.RequestInspector = LogRequest()
|
||||
vnetClient.ResponseInspector = LogResponse()
|
||||
|
||||
...
|
||||
|
||||
func LogRequest() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
dump, _ := httputil.DumpRequestOut(r, true)
|
||||
log.Println(string(dump))
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func LogResponse() autorest.RespondDecorator {
|
||||
return func(p autorest.Responder) autorest.Responder {
|
||||
return autorest.ResponderFunc(func(r *http.Response) error {
|
||||
err := p.Respond(r)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
dump, _ := httputil.DumpResponse(r, true)
|
||||
log.Println(string(dump))
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tracing and Metrics
|
||||
|
||||
All packages and the runtime are instrumented using [OpenCensus](https://opencensus.io/).
|
||||
|
||||
### Enable
|
||||
|
||||
As of now, tracing is disabled by default. There are 2 ways to enable tracing:
|
||||
|
||||
- set the environment variable `AZURE_SDK_TRACING_ENABLED` (_Recommended_)
|
||||
- alternatively, import the `github.com/Azure/go-autorest/tracing` package and call the `tracing.Enable()` function or `tracing.EnableWithAIForwarding()` if using the [App Insights Forwarder](https://docs.microsoft.com/en-us/azure/application-insights/opencensus-local-forwarder).
|
||||
|
||||
**Note**: In future major releases of the SDK, tracing may become enabled by default.
|
||||
|
||||
### Usage
|
||||
|
||||
Once enabled, all SDK calls will emit traces and metrics and the traces will correlate the SDK calls with the raw http calls made to Azure API's. To consume those traces, if are not doing it yet, you need to register an exporter of your choice such as [Azure App Insights](https://docs.microsoft.com/en-us/azure/application-insights/opencensus-local-forwarder) or [Zipkin](https://opencensus.io/quickstart/go/tracing/#exporting-traces).
|
||||
|
||||
To correlate the SDK calls between them and with the rest of your code, pass in a context that has a span initiated using the [opencensus-go library](https://github.com/census-instrumentation/opencensus-go) using the `trace.Startspan(ctx context.Context, name string, o ...StartOption)` function. Here is an example:
|
||||
|
||||
```go
|
||||
func doAzureCalls() {
|
||||
// The resulting context will be initialized with a root span as the context passed to
|
||||
// trace.StartSpan() has no existing span.
|
||||
ctx, span := trace.StartSpan(context.Background(),"doAzureCalls", trace.WithSampler(trace.AlwaysSample()))
|
||||
defer span.End()
|
||||
|
||||
// The traces from the SDK calls will be correlated under the span inside the context that is passed in.
|
||||
zone, _ := zonesClient.CreateOrUpdate(ctx, rg, zoneName, dns.Zone{Location: to.StringPtr("global")}, "", "")
|
||||
zone, _ = zonesClient.Get(ctx, rg, *zone.Name)
|
||||
for i := 0; i < rrCount; i++ {
|
||||
rr, _ := recordsClient.CreateOrUpdate(ctx, rg, zoneName, fmt.Sprintf("rr%d", i), dns.CNAME, rdSet{
|
||||
RecordSetProperties: &dns.RecordSetProperties{
|
||||
TTL: to.Int64Ptr(3600),
|
||||
CnameRecord: &dns.CnameRecord{
|
||||
Cname: to.StringPtr("vladdbCname"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"",
|
||||
"",
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Resources
|
||||
|
||||
- SDK docs are at [godoc.org](https://godoc.org/github.com/Azure/azure-sdk-for-go/).
|
||||
- SDK samples are at [Azure-Samples/azure-sdk-for-go-samples](https://github.com/Azure-Samples/azure-sdk-for-go-samples).
|
||||
- SDK notifications are published via the [Azure update feed](https://azure.microsoft.com/updates/).
|
||||
- Azure API docs are at [docs.microsoft.com/rest/api](https://docs.microsoft.com/rest/api/).
|
||||
- General Azure docs are at [docs.microsoft.com/azure](https://docs.microsoft.com/azure).
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0, see [LICENSE](./LICENSE).
|
||||
|
||||
## Contribute
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
[samples_repo]: https://github.com/Azure-Samples/azure-sdk-for-go-samples
|
||||
26
vendor/github.com/Azure/azure-sdk-for-go/doc.go
generated
vendored
26
vendor/github.com/Azure/azure-sdk-for-go/doc.go
generated
vendored
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
Package sdk provides Go packages for managing and using Azure services.
|
||||
|
||||
GitHub repo: https://github.com/Azure/azure-sdk-for-go
|
||||
|
||||
Official documentation: https://docs.microsoft.com/go/azure
|
||||
|
||||
API reference: https://godoc.org/github.com/Azure/azure-sdk-for-go
|
||||
|
||||
Samples: https://github.com/Azure-Samples/azure-sdk-for-go-samples
|
||||
*/
|
||||
package sdk
|
||||
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
1
vendor/github.com/Azure/azure-sdk-for-go/findTestedPackages.sh
generated
vendored
1
vendor/github.com/Azure/azure-sdk-for-go/findTestedPackages.sh
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
dirname $(find | grep _test.go | grep -v vendor) | sort -u
|
||||
15
vendor/github.com/Azure/azure-sdk-for-go/rungas.sh
generated
vendored
15
vendor/github.com/Azure/azure-sdk-for-go/rungas.sh
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
#!/bin/bash
|
||||
GITBRANCH=`git rev-parse --abbrev-ref HEAD`
|
||||
#We intend to only run gas on release branches.
|
||||
if [ "master" != $GITBRANCH ]; then
|
||||
exit 0
|
||||
fi
|
||||
REALEXITSTATUS=0
|
||||
go get -u github.com/HewlettPackard/gas
|
||||
gas -skip=*/arm/*/models.go -skip=*/management/examples/*.go -skip=*vendor* -skip=*/Gododir/* ./... | tee /dev/stderr
|
||||
REALEXITSTATUS=$(($REALEXITSTATUS+$?))
|
||||
gas -exclude=G101 ./arm/... ./management/examples/... | tee /dev/stderr
|
||||
REALEXITSTATUS=$(($REALEXITSTATUS+$?))
|
||||
gas -exclude=G204 ./Gododir/... | tee /dev/stderr
|
||||
REALEXITSTATUS=$(($REALEXITSTATUS+$?))
|
||||
exit $REALEXITSTATUS
|
||||
27
vendor/github.com/Azure/azure-sdk-for-go/swagger_to_sdk_config.json
generated
vendored
27
vendor/github.com/Azure/azure-sdk-for-go/swagger_to_sdk_config.json
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"meta": {
|
||||
"after_scripts": [
|
||||
"dep ensure",
|
||||
"go generate ./profiles/generate.go",
|
||||
"gofmt -w ./profiles/",
|
||||
"gofmt -w ./services/"
|
||||
],
|
||||
"autorest_options": {
|
||||
"use": "@microsoft.azure/autorest.go@~2.1.127",
|
||||
"go": "",
|
||||
"verbose": "",
|
||||
"sdkrel:go-sdk-folder": ".",
|
||||
"multiapi": "",
|
||||
"use-onever": "",
|
||||
"preview-chk": ""
|
||||
},
|
||||
"repotag": "azure-sdk-for-go",
|
||||
"envs": {
|
||||
"sdkrel:GOPATH": "../../../.."
|
||||
},
|
||||
"advanced_options": {
|
||||
"clone_dir": "./src/github.com/Azure/azure-sdk-for-go"
|
||||
},
|
||||
"version": "0.2.0"
|
||||
}
|
||||
}
|
||||
728
vendor/github.com/Azure/go-autorest/CHANGELOG.md
generated
vendored
728
vendor/github.com/Azure/go-autorest/CHANGELOG.md
generated
vendored
|
|
@ -1,728 +0,0 @@
|
|||
# CHANGELOG
|
||||
|
||||
## v11.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added method `ServicePrincipalToken()` to `DeviceFlowConfig` type.
|
||||
|
||||
## v11.2.8
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Deprecate content in the `version` package. The functionality has been superseded by content in the `autorest` package.
|
||||
|
||||
## v11.2.7
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix environment variable name for enabling tracing from `AZURE_SDK_TRACING_ENABELD` to `AZURE_SDK_TRACING_ENABLED`.
|
||||
Note that for backward compatibility reasons, both will work until the next major version release of the package.
|
||||
|
||||
## v11.2.6
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- If zero bytes are read from a polling response body don't attempt to unmarshal them.
|
||||
|
||||
## v11.2.5
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Removed race condition in `autorest.DoRetryForStatusCodes`.
|
||||
|
||||
## v11.2.4
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Function `cli.ProfilePath` now respects environment `AZURE_CONFIG_DIR` if available.
|
||||
|
||||
## v11.2.1
|
||||
|
||||
NOTE: Versions of Go prior to 1.10 have been removed from CI as they no
|
||||
longer work with golint.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Method `MSIConfig.Authorizer` now supports user-assigned identities.
|
||||
- The adal package now reports its own user-agent string.
|
||||
|
||||
## v11.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added `tracing` package that enables instrumentation of HTTP and API calls.
|
||||
Setting the env variable `AZURE_SDK_TRACING_ENABLED` or calling `tracing.Enable`
|
||||
will start instrumenting the code for metrics and traces.
|
||||
Additionally, setting the env variable `OCAGENT_TRACE_EXPORTER_ENDPOINT` or
|
||||
calling `tracing.EnableWithAIForwarding` will start the instrumentation and connect to an
|
||||
App Insights Local Forwarder that is needs to be running. Note that if the
|
||||
AI Local Forwarder is not running tracking will still be enabled.
|
||||
By default, instrumentation is disabled. Once enabled, instrumentation can also
|
||||
be programatically disabled by calling `Disable`.
|
||||
- Added `DoneWithContext` call for checking LRO status. `Done` has been deprecated.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Don't use the initial request's context for LRO polling.
|
||||
- Don't override the `refreshLock` and the `http.Client` when unmarshalling `ServicePrincipalToken` if
|
||||
it is already set.
|
||||
|
||||
## v11.1.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- When creating a future always include the polling tracker even if there's a failure; this allows the underlying response to be obtained by the caller.
|
||||
|
||||
## v11.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added `auth.NewAuthorizerFromCLI` to create an authorizer configured from the Azure 2.0 CLI.
|
||||
- Added `adal.NewOAuthConfigWithAPIVersion` to create an OAuthConfig with the specified API version.
|
||||
|
||||
## v11.0.1
|
||||
|
||||
### New Features
|
||||
|
||||
- Added `x5c` header to client assertion for certificate Issuer+Subject Name authentication.
|
||||
|
||||
## v11.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- To handle differences between ADFS and AAD the following fields have had their types changed from `string` to `json.Number`
|
||||
- ExpiresIn
|
||||
- ExpiresOn
|
||||
- NotBefore
|
||||
|
||||
### New Features
|
||||
|
||||
- Added `auth.NewAuthorizerFromFileWithResource` to create an authorizer from the config file with the specified resource.
|
||||
- Setting a client's `PollingDuration` to zero will use the provided context to control a LRO's polling duration.
|
||||
|
||||
## v10.15.5
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- In `DoRetryForStatusCodes`, if a request's context is cancelled return the last response.
|
||||
|
||||
## v10.15.4
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- If a polling operation returns a failure status code return the associated error.
|
||||
|
||||
## v10.15.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Initialize the polling URL and method for an LRO tracker on each iteration, favoring the Azure-AsyncOperation header.
|
||||
|
||||
## v10.15.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use fmt.Fprint when printing request/response so that any escape sequences aren't treated as format specifiers.
|
||||
|
||||
## v10.15.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- If an LRO API returns a `Failed` provisioning state in the initial response return an error at that point so the caller doesn't have to poll.
|
||||
- For failed LROs without an OData v4 error include the response body in the error's `AdditionalInfo` field to aid in diagnosing the failure.
|
||||
|
||||
## v10.15.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Add initial support for request/response logging via setting environment variables.
|
||||
Setting `AZURE_GO_SDK_LOG_LEVEL` to `LogInfo` will log request/response
|
||||
without their bodies. To include the bodies set the log level to `LogDebug`.
|
||||
By default the logger writes to strerr, however it can also write to stdout or a file
|
||||
if specified in `AZURE_GO_SDK_LOG_FILE`. Note that if the specified file
|
||||
already exists it will be truncated.
|
||||
IMPORTANT: by default the logger will redact the Authorization and Ocp-Apim-Subscription-Key
|
||||
headers. Any other secrets will _not_ be redacted.
|
||||
|
||||
## v10.14.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added package version that contains version constants and user-agent data.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add the user-agent to token requests.
|
||||
|
||||
## v10.13.0
|
||||
|
||||
- Added support for additionalInfo in ServiceError type.
|
||||
|
||||
## v10.12.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added field ServicePrincipalToken.MaxMSIRefreshAttempts to configure the maximun number of attempts to refresh an MSI token.
|
||||
|
||||
## v10.11.4
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- If an LRO returns http.StatusOK on the initial response with no async headers return the response body from Future.GetResult().
|
||||
- If there is no "final GET URL" return an error from Future.GetResult().
|
||||
|
||||
## v10.11.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- In IMDS retry logic, if we don't receive a response don't retry.
|
||||
- Renamed the retry function so it's clear it's meant for IMDS only.
|
||||
- For error response bodies that aren't OData-v4 compliant stick the raw JSON in the ServiceError.Details field so the information isn't lost.
|
||||
- Also add the raw HTTP response to the DetailedResponse.
|
||||
- Removed superfluous wrapping of response error in azure.DoRetryWithRegistration().
|
||||
|
||||
## v10.11.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Validation for integers handles int and int64 types.
|
||||
|
||||
## v10.11.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Adding User information to authorization config as parsed from CLI cache.
|
||||
|
||||
## v10.11.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added NewServicePrincipalTokenFromManualTokenSecret for creating a new SPT using a manual token and secret
|
||||
- Added method ServicePrincipalToken.MarshalTokenJSON() to marshall the inner Token
|
||||
|
||||
## v10.10.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Most ServicePrincipalTokens can now be marshalled/unmarshall to/from JSON (ServicePrincipalCertificateSecret and ServicePrincipalMSISecret are not supported).
|
||||
- Added method ServicePrincipalToken.SetRefreshCallbacks().
|
||||
|
||||
## v10.9.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Refreshing a refresh token obtained from a web app authorization code now works.
|
||||
|
||||
## v10.9.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- The retry logic for MSI token requests now uses exponential backoff per the guidelines.
|
||||
- IsTemporaryNetworkError() will return true for errors that don't implement the net.Error interface.
|
||||
|
||||
## v10.9.0
|
||||
|
||||
### Deprecated Methods
|
||||
|
||||
| Old Method | New Method |
|
||||
| -------------------------: | :---------------------------: |
|
||||
| azure.NewFuture() | azure.NewFutureFromResponse() |
|
||||
| Future.WaitForCompletion() | Future.WaitForCompletionRef() |
|
||||
|
||||
### New Features
|
||||
|
||||
- Added azure.NewFutureFromResponse() for creating a Future from the initial response from an async operation.
|
||||
- Added Future.GetResult() for making the final GET call to retrieve the result from an async operation.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Some futures failed to return their results, this should now be fixed.
|
||||
|
||||
## v10.8.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add nil-gaurd to token retry logic.
|
||||
|
||||
## v10.8.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Return a TokenRefreshError if the sender fails on the initial request.
|
||||
- Don't retry on non-temporary network errors.
|
||||
|
||||
## v10.8.0
|
||||
|
||||
- Added NewAuthorizerFromEnvironmentWithResource() helper function.
|
||||
|
||||
## v10.7.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added \*WithContext() methods to ADAL token refresh operations.
|
||||
|
||||
## v10.6.2
|
||||
|
||||
- Fixed a bug on device authentication.
|
||||
|
||||
## v10.6.1
|
||||
|
||||
- Added retries to MSI token get request.
|
||||
|
||||
## v10.6.0
|
||||
|
||||
- Changed MSI token implementation. Now, the token endpoint is the IMDS endpoint.
|
||||
|
||||
## v10.5.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- `DeviceFlowConfig.Authorizer()` now prints the device code message when running `go test`. `-v` flag is required.
|
||||
|
||||
## v10.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added NewPollingRequestWithContext() for use with polling asynchronous operations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Make retry logic use the request's context instead of the deprecated Cancel object.
|
||||
|
||||
## v10.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added helper for parsing Azure Resource ID's.
|
||||
- Added deprecation message to utils.GetEnvVarOrExit()
|
||||
|
||||
## v10.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added EnvironmentFromURL method to load an Environment from a given URL. This function is particularly useful in the private and hybrid Cloud model, where one may define their own endpoints
|
||||
- Added TokenAudience endpoint to Environment structure. This is useful in private and hybrid cloud models where TokenAudience endpoint can be different from ResourceManagerEndpoint
|
||||
|
||||
## v10.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added endpoints for batch management.
|
||||
|
||||
## v10.1.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- In Client.Do() invoke WithInspection() last so that it will inspect WithAuthorization().
|
||||
- Fixed authorization methods to invoke p.Prepare() first, aligning them with the other preparers.
|
||||
|
||||
## v10.1.2
|
||||
|
||||
- Corrected comment for auth.NewAuthorizerFromFile() function.
|
||||
|
||||
## v10.1.1
|
||||
|
||||
- Updated version number to match current release.
|
||||
|
||||
## v10.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Expose the polling URL for futures.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add validation.NewErrorWithValidationError back to prevent breaking changes (it is deprecated).
|
||||
|
||||
## v10.0.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added target and innererror fields to ServiceError to comply with OData v4 spec.
|
||||
- The Done() method on futures will now return a ServiceError object when available (it used to return a partial value of such errors).
|
||||
- Added helper methods for obtaining authorizers.
|
||||
- Expose the polling URL for futures.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Switched from glide to dep for dependency management.
|
||||
- Fixed unmarshaling of ServiceError for JSON bodies that don't conform to the OData spec.
|
||||
- Fixed a race condition in token refresh.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- The ServiceError.Details field type has been changed to match the OData v4 spec.
|
||||
- Go v1.7 has been dropped from CI.
|
||||
- API parameter validation failures will now return a unique error type validation.Error.
|
||||
- The adal.Token type has been decomposed from adal.ServicePrincipalToken (this was necessary in order to fix the token refresh race).
|
||||
|
||||
## v9.10.0
|
||||
|
||||
- Fix the Service Bus suffix in Azure public env
|
||||
- Add Service Bus Endpoint (AAD ResourceURI) for use in [Azure Service Bus RBAC Preview](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-role-based-access-control)
|
||||
|
||||
## v9.9.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added EventGridKeyAuthorizer for key authorization with event grid topics.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed race condition when auto-refreshing service principal tokens.
|
||||
|
||||
## v9.8.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Added http.StatusNoContent (204) to the list of expected status codes for long-running operations.
|
||||
- Updated runtime version info so it's current.
|
||||
|
||||
## v9.8.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added type azure.AsyncOpIncompleteError to be returned from a future's Result() method when the operation has not completed.
|
||||
|
||||
## v9.7.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use correct AAD and Graph endpoints for US Gov environment.
|
||||
|
||||
## v9.7.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for application/octet-stream MIME types.
|
||||
|
||||
## v9.6.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Ensure Authorization header is added to request when polling for registration status.
|
||||
|
||||
## v9.6.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for acquiring tokens via MSI with a user assigned identity.
|
||||
|
||||
## v9.5.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Don't remove encoding of existing URL Query parameters when calling autorest.WithQueryParameters.
|
||||
- Set correct Content Type when using autorest.WithFormData.
|
||||
|
||||
## v9.5.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Check for nil \*http.Response before dereferencing it.
|
||||
|
||||
## v9.5.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Don't count http.StatusTooManyRequests (429) against the retry cap.
|
||||
- Use retry logic when SkipResourceProviderRegistration is set to true.
|
||||
|
||||
## v9.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for username + password, API key, authoriazation code and cognitive services authentication.
|
||||
- Added field SkipResourceProviderRegistration to clients to provide a way to skip auto-registration of RPs.
|
||||
- Added utility function AsStringSlice() to convert its parameters to a string slice.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- When checking for authentication failures look at the error type not the status code as it could vary.
|
||||
|
||||
## v9.4.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Validate parameters when creating credentials.
|
||||
- Don't retry requests if the returned status is a 401 (http.StatusUnauthorized) as it will never succeed.
|
||||
|
||||
## v9.4.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Update the AccessTokensPath() to read access tokens path through AZURE_ACCESS_TOKEN_FILE. If this
|
||||
environment variable is not set, it will fall back to use default path set by Azure CLI.
|
||||
- Use case-insensitive string comparison for polling states.
|
||||
|
||||
## v9.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added WaitForCompletion() to Future as a default polling implementation.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Method Future.Done() shouldn't update polling status for unexpected HTTP status codes.
|
||||
|
||||
## v9.3.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- DoRetryForStatusCodes will retry if sender.Do returns a non-nil error.
|
||||
|
||||
## v9.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added PollingMethod() to Future so callers know what kind of polling mechanism is used.
|
||||
- Added azure.ChangeToGet() which transforms an http.Request into a GET (to be used with LROs).
|
||||
|
||||
## v9.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for custom Azure Stack endpoints.
|
||||
- Added type azure.Future used to track the status of long-running operations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Preserve the original error in DoRetryWithRegistration when registration fails.
|
||||
|
||||
## v9.1.1
|
||||
|
||||
- Fixes a bug regarding the cookie jar on `autorest.Client.Sender`.
|
||||
|
||||
## v9.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
- In cases where there is a non-empty error from the service, attempt to unmarshal it instead of uniformly calling it an "Unknown" error.
|
||||
- Support for loading Azure CLI Authentication files.
|
||||
- Automatically register your subscription with the Azure Resource Provider if it hadn't been previously.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- RetriableRequest can now tolerate a ReadSeekable body being read but not reset.
|
||||
- Adding missing Apache Headers
|
||||
|
||||
## v9.0.0
|
||||
|
||||
> **IMPORTANT:** This release was intially labeled incorrectly as `v8.4.0`. From the time it was released, it should have been marked `v9.0.0` because it contains breaking changes to the MSI packages. We appologize for any inconvenience this causes.
|
||||
|
||||
Adding MSI Endpoint Support and CLI token rehydration.
|
||||
|
||||
## v8.3.1
|
||||
|
||||
Pick up bug fix in adal for MSI support.
|
||||
|
||||
## v8.3.0
|
||||
|
||||
Updates to Error string formats for clarity. Also, adding a copy of the http.Response to errors for an improved debugging experience.
|
||||
|
||||
## v8.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Add support for bearer authentication callbacks
|
||||
- Support 429 response codes that include "Retry-After" header
|
||||
- Support validation constraint "Pattern" for map keys
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Make RetriableRequest work with multiple versions of Go
|
||||
|
||||
## v8.1.1
|
||||
|
||||
Updates the RetriableRequest to take advantage of GetBody() added in Go 1.8.
|
||||
|
||||
## v8.1.0
|
||||
|
||||
Adds RetriableRequest type for more efficient handling of retrying HTTP requests.
|
||||
|
||||
## v8.0.0
|
||||
|
||||
ADAL refactored into its own package.
|
||||
Support for UNIX time.
|
||||
|
||||
## v7.3.1
|
||||
|
||||
- Version Testing now removed from production bits that are shipped with the library.
|
||||
|
||||
## v7.3.0
|
||||
|
||||
- Exposing new `RespondDecorator`, `ByDiscardingBody`. This allows operations
|
||||
to acknowledge that they do not need either the entire or a trailing portion
|
||||
of accepts response body. In doing so, Go's http library can reuse HTTP
|
||||
connections more readily.
|
||||
- Adding `PrepareDecorator` to target custom BaseURLs.
|
||||
- Adding ACR suffix to public cloud environment.
|
||||
- Updating Glide dependencies.
|
||||
|
||||
## v7.2.5
|
||||
|
||||
- Fixed the Active Directory endpoint for the China cloud.
|
||||
- Removes UTF-8 BOM if present in response payload.
|
||||
- Added telemetry.
|
||||
|
||||
## v7.2.3
|
||||
|
||||
- Fixing bug in calls to `DelayForBackoff` that caused doubling of delay
|
||||
duration.
|
||||
|
||||
## v7.2.2
|
||||
|
||||
- autorest/azure: added ASM and ARM VM DNS suffixes.
|
||||
|
||||
## v7.2.1
|
||||
|
||||
- fixed parsing of UTC times that are not RFC3339 conformant.
|
||||
|
||||
## v7.2.0
|
||||
|
||||
- autorest/validation: Reformat validation error for better error message.
|
||||
|
||||
## v7.1.0
|
||||
|
||||
- preparer: Added support for multipart formdata - WithMultiPartFormdata()
|
||||
- preparer: Added support for sending file in request body - WithFile
|
||||
- client: Added RetryDuration parameter.
|
||||
- autorest/validation: new package for validation code for Azure Go SDK.
|
||||
|
||||
## v7.0.7
|
||||
|
||||
- Add trailing / to endpoint
|
||||
- azure: add EnvironmentFromName
|
||||
|
||||
## v7.0.6
|
||||
|
||||
- Add retry logic for 408, 500, 502, 503 and 504 status codes.
|
||||
- Change url path and query encoding logic.
|
||||
- Fix DelayForBackoff for proper exponential delay.
|
||||
- Add CookieJar in Client.
|
||||
|
||||
## v7.0.5
|
||||
|
||||
- Add check to start polling only when status is in [200,201,202].
|
||||
- Refactoring for unchecked errors.
|
||||
- azure/persist changes.
|
||||
- Fix 'file in use' issue in renewing token in deviceflow.
|
||||
- Store header RetryAfter for subsequent requests in polling.
|
||||
- Add attribute details in service error.
|
||||
|
||||
## v7.0.4
|
||||
|
||||
- Better error messages for long running operation failures
|
||||
|
||||
## v7.0.3
|
||||
|
||||
- Corrected DoPollForAsynchronous to properly handle the initial response
|
||||
|
||||
## v7.0.2
|
||||
|
||||
- Corrected DoPollForAsynchronous to continue using the polling method first discovered
|
||||
|
||||
## v7.0.1
|
||||
|
||||
- Fixed empty JSON input error in ByUnmarshallingJSON
|
||||
- Fixed polling support for GET calls
|
||||
- Changed format name from TimeRfc1123 to TimeRFC1123
|
||||
|
||||
## v7.0.0
|
||||
|
||||
- Added ByCopying responder with supporting TeeReadCloser
|
||||
- Rewrote Azure asynchronous handling
|
||||
- Reverted to only unmarshalling JSON
|
||||
- Corrected handling of RFC3339 time strings and added support for Rfc1123 time format
|
||||
|
||||
The `json.Decoder` does not catch bad data as thoroughly as `json.Unmarshal`. Since
|
||||
`encoding/json` successfully deserializes all core types, and extended types normally provide
|
||||
their custom JSON serialization handlers, the code has been reverted back to using
|
||||
`json.Unmarshal`. The original change to use `json.Decode` was made to reduce duplicate
|
||||
code; there is no loss of function, and there is a gain in accuracy, by reverting.
|
||||
|
||||
Additionally, Azure services indicate requests to be polled by multiple means. The existing code
|
||||
only checked for one of those (that is, the presence of the `Azure-AsyncOperation` header).
|
||||
The new code correctly covers all cases and aligns with the other Azure SDKs.
|
||||
|
||||
## v6.1.0
|
||||
|
||||
- Introduced `date.ByUnmarshallingJSONDate` and `date.ByUnmarshallingJSONTime` to enable JSON encoded values.
|
||||
|
||||
## v6.0.0
|
||||
|
||||
- Completely reworked the handling of polled and asynchronous requests
|
||||
- Removed unnecessary routines
|
||||
- Reworked `mocks.Sender` to replay a series of `http.Response` objects
|
||||
- Added `PrepareDecorators` for primitive types (e.g., bool, int32)
|
||||
|
||||
Handling polled and asynchronous requests is no longer part of `Client#Send`. Instead new
|
||||
`SendDecorators` implement different styles of polled behavior. See`autorest.DoPollForStatusCodes`
|
||||
and `azure.DoPollForAsynchronous` for examples.
|
||||
|
||||
## v5.0.0
|
||||
|
||||
- Added new RespondDecorators unmarshalling primitive types
|
||||
- Corrected application of inspection and authorization PrependDecorators
|
||||
|
||||
## v4.0.0
|
||||
|
||||
- Added support for Azure long-running operations.
|
||||
- Added cancelation support to all decorators and functions that may delay.
|
||||
- Breaking: `DelayForBackoff` now accepts a channel, which may be nil.
|
||||
|
||||
## v3.1.0
|
||||
|
||||
- Add support for OAuth Device Flow authorization.
|
||||
- Add support for ServicePrincipalTokens that are backed by an existing token, rather than other secret material.
|
||||
- Add helpers for persisting and restoring Tokens.
|
||||
- Increased code coverage in the github.com/Azure/autorest/azure package
|
||||
|
||||
## v3.0.0
|
||||
|
||||
- Breaking: `NewErrorWithError` no longer takes `statusCode int`.
|
||||
- Breaking: `NewErrorWithStatusCode` is replaced with `NewErrorWithResponse`.
|
||||
- Breaking: `Client#Send()` no longer takes `codes ...int` argument.
|
||||
- Add: XML unmarshaling support with `ByUnmarshallingXML()`
|
||||
- Stopped vending dependencies locally and switched to [Glide](https://github.com/Masterminds/glide).
|
||||
Applications using this library should either use Glide or vendor dependencies locally some other way.
|
||||
- Add: `azure.WithErrorUnlessStatusCode()` decorator to handle Azure errors.
|
||||
- Fix: use `net/http.DefaultClient` as base client.
|
||||
- Fix: Missing inspection for polling responses added.
|
||||
- Add: CopyAndDecode helpers.
|
||||
- Improved `./autorest/to` with `[]string` helpers.
|
||||
- Removed golint suppressions in .travis.yml.
|
||||
|
||||
## v2.1.0
|
||||
|
||||
- Added `StatusCode` to `Error` for more easily obtaining the HTTP Reponse StatusCode (if any)
|
||||
|
||||
## v2.0.0
|
||||
|
||||
- Changed `to.StringMapPtr` method signature to return a pointer
|
||||
- Changed `ServicePrincipalCertificateSecret` and `NewServicePrincipalTokenFromCertificate` to support generic certificate and private keys
|
||||
|
||||
## v1.0.0
|
||||
|
||||
- Added Logging inspectors to trace http.Request / Response
|
||||
- Added support for User-Agent header
|
||||
- Changed WithHeader PrepareDecorator to use set vs. add
|
||||
- Added JSON to error when unmarshalling fails
|
||||
- Added Client#Send method
|
||||
- Corrected case of "Azure" in package paths
|
||||
- Added "to" helpers, Azure helpers, and improved ease-of-use
|
||||
- Corrected golint issues
|
||||
|
||||
## v1.0.1
|
||||
|
||||
- Added CHANGELOG.md
|
||||
|
||||
## v1.1.0
|
||||
|
||||
- Added mechanism to retrieve a ServicePrincipalToken using a certificate-signed JWT
|
||||
- Added an example of creating a certificate-based ServicePrincipal and retrieving an OAuth token using the certificate
|
||||
|
||||
## v1.1.1
|
||||
|
||||
- Introduce godeps and vendor dependencies introduced in v1.1.1
|
||||
23
vendor/github.com/Azure/go-autorest/GNUmakefile
generated
vendored
23
vendor/github.com/Azure/go-autorest/GNUmakefile
generated
vendored
|
|
@ -1,23 +0,0 @@
|
|||
DIR?=./autorest/
|
||||
|
||||
default: build
|
||||
|
||||
build: fmt
|
||||
go install $(DIR)
|
||||
|
||||
test:
|
||||
go test $(DIR) || exit 1
|
||||
|
||||
vet:
|
||||
@echo "go vet ."
|
||||
@go vet $(DIR)... ; if [ $$? -eq 1 ]; then \
|
||||
echo ""; \
|
||||
echo "Vet found suspicious constructs. Please check the reported constructs"; \
|
||||
echo "and fix them if necessary before submitting the code for review."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
fmt:
|
||||
gofmt -w $(DIR)
|
||||
|
||||
.PHONY: build test vet fmt
|
||||
247
vendor/github.com/Azure/go-autorest/Gopkg.lock
generated
vendored
247
vendor/github.com/Azure/go-autorest/Gopkg.lock
generated
vendored
|
|
@ -1,247 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e1b859e3d9e90007d5fbf25edf57733b224f1857f6592636130afab3af8cfae7"
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e0a4505d5cf7ac6b5d92e3aee79d838b5f1ae8e9641ec7fa5d1e9b01d7a7ea95"
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = [
|
||||
"gen-go/agent/common/v1",
|
||||
"gen-go/agent/trace/v1",
|
||||
"gen-go/trace/v1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "24333298e36590ea0716598caacc8959fc393c48"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0deddd908b6b4b768cfc272c16ee61e7088a60f7fe2f06c547bd3d8e1f8b8e77"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = ""
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6098222470fe0172157ce9bbef5d2200df4edde17ee649c5d6e48330e4afa4c6"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7f175a633086a933d1940a7e7dc2154a0070a7c25fb4a2f671f3eef1a34d1fd7"
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5448fe645cb1964ba70ac8f9f2ffe975e61a536c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = ""
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ad67dfd3799a2c58f6c65871dd141d8b53f61f600aec48ce8d7fa16a4d5476f8"
|
||||
name = "go.opencensus.io"
|
||||
packages = [
|
||||
".",
|
||||
"exemplar",
|
||||
"internal",
|
||||
"internal/tagencoding",
|
||||
"plugin/ochttp",
|
||||
"plugin/ochttp/propagation/b3",
|
||||
"plugin/ochttp/propagation/tracecontext",
|
||||
"stats",
|
||||
"stats/internal",
|
||||
"stats/view",
|
||||
"tag",
|
||||
"trace",
|
||||
"trace/internal",
|
||||
"trace/propagation",
|
||||
"trace/tracestate",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:78f41d38365ccef743e54ed854a2faf73313ba0750c621116a8eeb0395590bd0"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"pkcs12",
|
||||
"pkcs12/internal/rc2",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "0c41d7ab0a0ee717d4590a44bcb987dfd9e183eb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:547dcb6aebfb7fb17947660ebb034470c13f4d63d893def190a2f7ba3d09bc38"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "49bb7cea24b1df9410e1712aa6433dae904ff66a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2ed0bf267e44950120acd95570227e28184573ffb099bd85b529ee148e004ddb"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = ""
|
||||
revision = "fa43e7bc11baaae89f3f902b2b4d832b68234844"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ca2e72555afbcebdead7c961b135650b5111dbbaf37a874de63976fdda57f129"
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
pruneopts = ""
|
||||
revision = "c51f30376ab7ec4f22b65de846a41593c8b70f07"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:1b3b4ec811695907c4a3cb92e4f32834a4a42459bff7e02068b6b2b5344803cd"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = ""
|
||||
revision = "af9cb2a35e7f169ec875002c1829c9b315cddc04"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:15656947b87a6a240e61dcfae9e71a55a8d5677f240d12ab48f02cdbabf1e309"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1"
|
||||
version = "v1.15.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"contrib.go.opencensus.io/exporter/ocagent",
|
||||
"github.com/dgrijalva/jwt-go",
|
||||
"github.com/dimchansky/utfbom",
|
||||
"github.com/mitchellh/go-homedir",
|
||||
"github.com/stretchr/testify/require",
|
||||
"go.opencensus.io/plugin/ochttp",
|
||||
"go.opencensus.io/plugin/ochttp/propagation/tracecontext",
|
||||
"go.opencensus.io/stats/view",
|
||||
"go.opencensus.io/trace",
|
||||
"golang.org/x/crypto/pkcs12",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
45
vendor/github.com/Azure/go-autorest/Gopkg.toml
generated
vendored
45
vendor/github.com/Azure/go-autorest/Gopkg.toml
generated
vendored
|
|
@ -1,45 +0,0 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "3.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "go.opencensus.io"
|
||||
version = "0.18.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
version = "0.2.0"
|
||||
149
vendor/github.com/Azure/go-autorest/README.md
generated
vendored
149
vendor/github.com/Azure/go-autorest/README.md
generated
vendored
|
|
@ -1,149 +0,0 @@
|
|||
# go-autorest
|
||||
|
||||
[](https://godoc.org/github.com/Azure/go-autorest/autorest)
|
||||
[](https://travis-ci.org/Azure/go-autorest)
|
||||
[](https://goreportcard.com/report/Azure/go-autorest)
|
||||
|
||||
Package go-autorest provides an HTTP request client for use with [Autorest](https://github.com/Azure/autorest.go)-generated API client packages.
|
||||
|
||||
An authentication client tested with Azure Active Directory (AAD) is also
|
||||
provided in this repo in the package
|
||||
`github.com/Azure/go-autorest/autorest/adal`. Despite its name, this package
|
||||
is maintained only as part of the Azure Go SDK and is not related to other
|
||||
"ADAL" libraries in [github.com/AzureAD](https://github.com/AzureAD).
|
||||
|
||||
## Overview
|
||||
|
||||
Package go-autorest implements an HTTP request pipeline suitable for use across
|
||||
multiple goroutines and provides the shared routines used by packages generated
|
||||
by [Autorest](https://github.com/Azure/autorest.go).
|
||||
|
||||
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
|
||||
and Responding. A typical pattern is:
|
||||
|
||||
```go
|
||||
req, err := Prepare(&http.Request{},
|
||||
token.WithAuthorization())
|
||||
|
||||
resp, err := Send(req,
|
||||
WithLogging(logger),
|
||||
DoErrorIfStatusCode(http.StatusInternalServerError),
|
||||
DoCloseIfError(),
|
||||
DoRetryForAttempts(5, time.Second))
|
||||
|
||||
err = Respond(resp,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
```
|
||||
|
||||
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
||||
and then pass the data along, pass the data first and then modify the result, or wrap themselves
|
||||
around passing the data (such as a logger might do). Decorators run in the order provided. For
|
||||
example, the following:
|
||||
|
||||
```go
|
||||
req, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPath("a"),
|
||||
WithPath("b"),
|
||||
WithPath("c"))
|
||||
```
|
||||
|
||||
will set the URL to:
|
||||
|
||||
```
|
||||
https://microsoft.com/a/b/c
|
||||
```
|
||||
|
||||
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
|
||||
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
|
||||
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
|
||||
all bound together by means of input / output channels.
|
||||
|
||||
Decorators hold their passed state within a closure (such as the path components in the example
|
||||
above). Be careful to share Preparers and Responders only in a context where such held state
|
||||
applies. For example, it may not make sense to share a Preparer that applies a query string from a
|
||||
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
|
||||
struct (e.g., `ByUnmarshallingJson`) is likely incorrect.
|
||||
|
||||
Errors raised by autorest objects and methods will conform to the `autorest.Error` interface.
|
||||
|
||||
See the included examples for more detail. For details on the suggested use of this package by
|
||||
generated clients, see the Client described below.
|
||||
|
||||
## Helpers
|
||||
|
||||
### Handling Swagger Dates
|
||||
|
||||
The Swagger specification (https://swagger.io) that drives AutoRest
|
||||
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
|
||||
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure correct
|
||||
parsing and formatting.
|
||||
|
||||
### Handling Empty Values
|
||||
|
||||
In JSON, missing values have different semantics than empty values. This is especially true for
|
||||
services using the HTTP PATCH verb. The JSON submitted with a PATCH request generally contains
|
||||
only those values to modify. Missing values are to be left unchanged. Developers, then, require a
|
||||
means to both specify an empty value and to leave the value out of the submitted JSON.
|
||||
|
||||
The Go JSON package (`encoding/json`) supports the `omitempty` tag. When specified, it omits
|
||||
empty values from the rendered JSON. Since Go defines default values for all base types (such as ""
|
||||
for string and 0 for int) and provides no means to mark a value as actually empty, the JSON package
|
||||
treats default values as meaning empty, omitting them from the rendered JSON. This means that, using
|
||||
the Go base types encoded through the default JSON package, it is not possible to create JSON to
|
||||
clear a value at the server.
|
||||
|
||||
The workaround within the Go community is to use pointers to base types in lieu of base types within
|
||||
structures that map to JSON. For example, instead of a value of type `string`, the workaround uses
|
||||
`*string`. While this enables distinguishing empty values from those to be unchanged, creating
|
||||
pointers to a base type (notably constant, in-line values) requires additional variables. This, for
|
||||
example,
|
||||
|
||||
```go
|
||||
s := struct {
|
||||
S *string
|
||||
}{ S: &"foo" }
|
||||
```
|
||||
fails, while, this
|
||||
|
||||
```go
|
||||
v := "foo"
|
||||
s := struct {
|
||||
S *string
|
||||
}{ S: &v }
|
||||
```
|
||||
succeeds.
|
||||
|
||||
To ease using pointers, the subpackage `to` contains helpers that convert to and from pointers for
|
||||
Go base types which have Swagger analogs. It also provides a helper that converts between
|
||||
`map[string]string` and `map[string]*string`, enabling the JSON to specify that the value
|
||||
associated with a key should be cleared. With the helpers, the previous example becomes
|
||||
|
||||
```go
|
||||
s := struct {
|
||||
S *string
|
||||
}{ S: to.StringPtr("foo") }
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/Azure/go-autorest/autorest
|
||||
go get github.com/Azure/go-autorest/autorest/azure
|
||||
go get github.com/Azure/go-autorest/autorest/date
|
||||
go get github.com/Azure/go-autorest/autorest/to
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
See LICENSE file.
|
||||
|
||||
-----
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of
|
||||
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
|
||||
see the [Code of Conduct
|
||||
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
|
||||
questions or comments.
|
||||
292
vendor/github.com/Azure/go-autorest/autorest/adal/README.md
generated
vendored
292
vendor/github.com/Azure/go-autorest/autorest/adal/README.md
generated
vendored
|
|
@ -1,292 +0,0 @@
|
|||
# Azure Active Directory authentication for Go
|
||||
|
||||
This is a standalone package for authenticating with Azure Active
|
||||
Directory from other Go libraries and applications, in particular the [Azure SDK
|
||||
for Go](https://github.com/Azure/azure-sdk-for-go).
|
||||
|
||||
Note: Despite the package's name it is not related to other "ADAL" libraries
|
||||
maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues
|
||||
should be opened in [this repo's](https://github.com/Azure/go-autorest/issues)
|
||||
or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue
|
||||
trackers.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get -u github.com/Azure/go-autorest/autorest/adal
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
|
||||
|
||||
### Register an Azure AD Application with secret
|
||||
|
||||
|
||||
1. Register a new application with a `secret` credential
|
||||
|
||||
```
|
||||
az ad app create \
|
||||
--display-name example-app \
|
||||
--homepage https://example-app/home \
|
||||
--identifier-uris https://example-app/app \
|
||||
--password secret
|
||||
```
|
||||
|
||||
2. Create a service principal using the `Application ID` from previous step
|
||||
|
||||
```
|
||||
az ad sp create --id "Application ID"
|
||||
```
|
||||
|
||||
* Replace `Application ID` with `appId` from step 1.
|
||||
|
||||
### Register an Azure AD Application with certificate
|
||||
|
||||
1. Create a private key
|
||||
|
||||
```
|
||||
openssl genrsa -out "example-app.key" 2048
|
||||
```
|
||||
|
||||
2. Create the certificate
|
||||
|
||||
```
|
||||
openssl req -new -key "example-app.key" -subj "/CN=example-app" -out "example-app.csr"
|
||||
openssl x509 -req -in "example-app.csr" -signkey "example-app.key" -out "example-app.crt" -days 10000
|
||||
```
|
||||
|
||||
3. Create the PKCS12 version of the certificate containing also the private key
|
||||
|
||||
```
|
||||
openssl pkcs12 -export -out "example-app.pfx" -inkey "example-app.key" -in "example-app.crt" -passout pass:
|
||||
|
||||
```
|
||||
|
||||
4. Register a new application with the certificate content form `example-app.crt`
|
||||
|
||||
```
|
||||
certificateContents="$(tail -n+2 "example-app.crt" | head -n-1)"
|
||||
|
||||
az ad app create \
|
||||
--display-name example-app \
|
||||
--homepage https://example-app/home \
|
||||
--identifier-uris https://example-app/app \
|
||||
--key-usage Verify --end-date 2018-01-01 \
|
||||
--key-value "${certificateContents}"
|
||||
```
|
||||
|
||||
5. Create a service principal using the `Application ID` from previous step
|
||||
|
||||
```
|
||||
az ad sp create --id "APPLICATION_ID"
|
||||
```
|
||||
|
||||
* Replace `APPLICATION_ID` with `appId` from step 4.
|
||||
|
||||
|
||||
### Grant the necessary permissions
|
||||
|
||||
Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained
|
||||
level. There is a set of [pre-defined roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles)
|
||||
which can be assigned to a service principal of an Azure AD application depending of your needs.
|
||||
|
||||
```
|
||||
az role assignment create --assigner "SERVICE_PRINCIPAL_ID" --role "ROLE_NAME"
|
||||
```
|
||||
|
||||
* Replace the `SERVICE_PRINCIPAL_ID` with the `appId` from previous step.
|
||||
* Replace the `ROLE_NAME` with a role name of your choice.
|
||||
|
||||
It is also possible to define custom role definitions.
|
||||
|
||||
```
|
||||
az role definition create --role-definition role-definition.json
|
||||
```
|
||||
|
||||
* Check [custom roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
|
||||
|
||||
|
||||
### Acquire Access Token
|
||||
|
||||
The common configuration used by all flows:
|
||||
|
||||
```Go
|
||||
const activeDirectoryEndpoint = "https://login.microsoftonline.com/"
|
||||
tenantID := "TENANT_ID"
|
||||
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID)
|
||||
|
||||
applicationID := "APPLICATION_ID"
|
||||
|
||||
callback := func(token adal.Token) error {
|
||||
// This is called after the token is acquired
|
||||
}
|
||||
|
||||
// The resource for which the token is acquired
|
||||
resource := "https://management.core.windows.net/"
|
||||
```
|
||||
|
||||
* Replace the `TENANT_ID` with your tenant ID.
|
||||
* Replace the `APPLICATION_ID` with the value from previous section.
|
||||
|
||||
#### Client Credentials
|
||||
|
||||
```Go
|
||||
applicationSecret := "APPLICATION_SECRET"
|
||||
|
||||
spt, err := adal.NewServicePrincipalToken(
|
||||
oauthConfig,
|
||||
appliationID,
|
||||
applicationSecret,
|
||||
resource,
|
||||
callbacks...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Acquire a new access token
|
||||
err = spt.Refresh()
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
* Replace the `APPLICATION_SECRET` with the `password` value from previous section.
|
||||
|
||||
#### Client Certificate
|
||||
|
||||
```Go
|
||||
certificatePath := "./example-app.pfx"
|
||||
|
||||
certData, err := ioutil.ReadFile(certificatePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read the certificate file (%s): %v", certificatePath, err)
|
||||
}
|
||||
|
||||
// Get the certificate and private key from pfx file
|
||||
certificate, rsaPrivateKey, err := decodePkcs12(certData, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
|
||||
}
|
||||
|
||||
spt, err := adal.NewServicePrincipalTokenFromCertificate(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
certificate,
|
||||
rsaPrivateKey,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
// Acquire a new access token
|
||||
err = spt.Refresh()
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
* Update the certificate path to point to the example-app.pfx file which was created in previous section.
|
||||
|
||||
|
||||
#### Device Code
|
||||
|
||||
```Go
|
||||
oauthClient := &http.Client{}
|
||||
|
||||
// Acquire the device code
|
||||
deviceCode, err := adal.InitiateDeviceAuth(
|
||||
oauthClient,
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
resource)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to start device auth flow: %s", err)
|
||||
}
|
||||
|
||||
// Display the authentication message
|
||||
fmt.Println(*deviceCode.Message)
|
||||
|
||||
// Wait here until the user is authenticated
|
||||
token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to finish device auth flow: %s", err)
|
||||
}
|
||||
|
||||
spt, err := adal.NewServicePrincipalTokenFromManualToken(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
resource,
|
||||
*token,
|
||||
callbacks...)
|
||||
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
#### Username password authenticate
|
||||
|
||||
```Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromUsernamePassword(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
username,
|
||||
password,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
#### Authorization code authenticate
|
||||
|
||||
``` Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
clientSecret,
|
||||
authorizationCode,
|
||||
redirectURI,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
err = spt.Refresh()
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
### Command Line Tool
|
||||
|
||||
A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
|
||||
|
||||
```
|
||||
adal -h
|
||||
|
||||
Usage of ./adal:
|
||||
-applicationId string
|
||||
application id
|
||||
-certificatePath string
|
||||
path to pk12/PFC application certificate
|
||||
-mode string
|
||||
authentication mode (device, secret, cert, refresh) (default "device")
|
||||
-resource string
|
||||
resource for which the token is requested
|
||||
-secret string
|
||||
application secret
|
||||
-tenantId string
|
||||
tenant id
|
||||
-tokenCachePath string
|
||||
location of oath token cache (default "/home/cgc/.adal/accessToken.json")
|
||||
```
|
||||
|
||||
Example acquire a token for `https://management.core.windows.net/` using device code flow:
|
||||
|
||||
```
|
||||
adal -mode device \
|
||||
-applicationId "APPLICATION_ID" \
|
||||
-tenantId "TENANT_ID" \
|
||||
-resource https://management.core.windows.net/
|
||||
|
||||
```
|
||||
95
vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go
generated
vendored
95
vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go
generated
vendored
|
|
@ -1,95 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewOAuthConfig(t *testing.T) {
|
||||
const testActiveDirectoryEndpoint = "https://login.test.com"
|
||||
const testTenantID = "tenant-id-test"
|
||||
|
||||
config, err := NewOAuthConfig(testActiveDirectoryEndpoint, testTenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest/adal: Unexpected error while creating oauth configuration for tenant: %v.", err)
|
||||
}
|
||||
|
||||
expected := "https://login.test.com/tenant-id-test/oauth2/authorize?api-version=1.0"
|
||||
if config.AuthorizeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.AuthorizeEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/token?api-version=1.0"
|
||||
if config.TokenEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.TokenEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/devicecode?api-version=1.0"
|
||||
if config.DeviceCodeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal Incorrect devicecode url for Tenant from Environment. expected(%s). actual(%v).", expected, config.DeviceCodeEndpoint)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOAuthConfigWithAPIVersionNil(t *testing.T) {
|
||||
const testActiveDirectoryEndpoint = "https://login.test.com"
|
||||
const testTenantID = "tenant-id-test"
|
||||
|
||||
config, err := NewOAuthConfigWithAPIVersion(testActiveDirectoryEndpoint, testTenantID, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest/adal: Unexpected error while creating oauth configuration for tenant: %v.", err)
|
||||
}
|
||||
|
||||
expected := "https://login.test.com/tenant-id-test/oauth2/authorize"
|
||||
if config.AuthorizeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.AuthorizeEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/token"
|
||||
if config.TokenEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.TokenEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/devicecode"
|
||||
if config.DeviceCodeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal Incorrect devicecode url for Tenant from Environment. expected(%s). actual(%v).", expected, config.DeviceCodeEndpoint)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOAuthConfigWithAPIVersionNotNil(t *testing.T) {
|
||||
const testActiveDirectoryEndpoint = "https://login.test.com"
|
||||
const testTenantID = "tenant-id-test"
|
||||
apiVersion := "2.0"
|
||||
|
||||
config, err := NewOAuthConfigWithAPIVersion(testActiveDirectoryEndpoint, testTenantID, &apiVersion)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest/adal: Unexpected error while creating oauth configuration for tenant: %v.", err)
|
||||
}
|
||||
|
||||
expected := "https://login.test.com/tenant-id-test/oauth2/authorize?api-version=2.0"
|
||||
if config.AuthorizeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.AuthorizeEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/token?api-version=2.0"
|
||||
if config.TokenEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.TokenEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/devicecode?api-version=2.0"
|
||||
if config.DeviceCodeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal Incorrect devicecode url for Tenant from Environment. expected(%s). actual(%v).", expected, config.DeviceCodeEndpoint)
|
||||
}
|
||||
}
|
||||
330
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go
generated
vendored
330
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go
generated
vendored
|
|
@ -1,330 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
TestResource = "SomeResource"
|
||||
TestClientID = "SomeClientID"
|
||||
TestTenantID = "SomeTenantID"
|
||||
TestActiveDirectoryEndpoint = "https://login.test.com/"
|
||||
)
|
||||
|
||||
var (
|
||||
testOAuthConfig, _ = NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
|
||||
TestOAuthConfig = *testOAuthConfig
|
||||
)
|
||||
|
||||
const MockDeviceCodeResponse = `
|
||||
{
|
||||
"device_code": "10000-40-1234567890",
|
||||
"user_code": "ABCDEF",
|
||||
"verification_url": "http://aka.ms/deviceauth",
|
||||
"expires_in": "900",
|
||||
"interval": "0"
|
||||
}
|
||||
`
|
||||
|
||||
const MockDeviceTokenResponse = `{
|
||||
"access_token": "accessToken",
|
||||
"refresh_token": "refreshToken",
|
||||
"expires_in": "1000",
|
||||
"expires_on": "2000",
|
||||
"not_before": "3000",
|
||||
"resource": "resource",
|
||||
"token_type": "type"
|
||||
}
|
||||
`
|
||||
|
||||
func TestDeviceCodeIncludesResource(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(MockDeviceCodeResponse))
|
||||
|
||||
code, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err != nil {
|
||||
t.Fatalf("adal: unexpected error initiating device auth")
|
||||
}
|
||||
|
||||
if code.Resource != TestResource {
|
||||
t.Fatalf("adal: InitiateDeviceAuth failed to stash the resource in the DeviceCode struct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfSendingFails(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.SetError(fmt.Errorf("this is an error"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeSendingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeSendingFails, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfBadRequest(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("doesn't matter")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfCannotDeserializeDeviceCode(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockDeviceCodeResponse, "expires_in", "\":, :gibberish", -1)
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(gibberishJSON)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfEmptyDeviceCode(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err != ErrDeviceCodeEmpty {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", ErrDeviceCodeEmpty, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func deviceCode() *DeviceCode {
|
||||
var deviceCode DeviceCode
|
||||
_ = json.Unmarshal([]byte(MockDeviceCodeResponse), &deviceCode)
|
||||
deviceCode.Resource = TestResource
|
||||
deviceCode.ClientID = TestClientID
|
||||
return &deviceCode
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturns(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(MockDeviceTokenResponse)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("adal: got error unexpectedly")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfSendingFails(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.SetError(fmt.Errorf("this is an error"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenSendingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenSendingFails, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfServerError(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusInternalServerError, "Internal Server Error"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfCannotDeserializeDeviceToken(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockDeviceTokenResponse, "expires_in", ";:\"gibberish", -1)
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(gibberishJSON)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func errorDeviceTokenResponse(message string) string {
|
||||
return `{ "error": "` + message + `" }`
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfAuthorizationPending(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("authorization_pending"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := CheckForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceAuthorizationPending {
|
||||
t.Fatalf("!!!")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfSlowDown(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("slow_down"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := CheckForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceSlowDown {
|
||||
t.Fatalf("!!!")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
type deviceTokenSender struct {
|
||||
errorString string
|
||||
attempts int
|
||||
}
|
||||
|
||||
func newDeviceTokenSender(deviceErrorString string) *deviceTokenSender {
|
||||
return &deviceTokenSender{errorString: deviceErrorString, attempts: 0}
|
||||
}
|
||||
|
||||
func (s *deviceTokenSender) Do(req *http.Request) (*http.Response, error) {
|
||||
var resp *http.Response
|
||||
if s.attempts < 1 {
|
||||
s.attempts++
|
||||
resp = mocks.NewResponseWithContent(errorDeviceTokenResponse(s.errorString))
|
||||
} else {
|
||||
resp = mocks.NewResponseWithContent(MockDeviceTokenResponse)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// since the above only exercise CheckForUserCompletion, we repeat the test here,
|
||||
// but with the intent of showing that WaitForUserCompletion loops properly.
|
||||
func TestDeviceTokenSucceedsWithIntermediateAuthPending(t *testing.T) {
|
||||
sender := newDeviceTokenSender("authorization_pending")
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
// same as above but with SlowDown now
|
||||
func TestDeviceTokenSucceedsWithIntermediateSlowDown(t *testing.T) {
|
||||
sender := newDeviceTokenSender("slow_down")
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfAccessDenied(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("access_denied"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceAccessDenied {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceAccessDenied.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfCodeExpired(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("code_expired"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceCodeExpired {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceCodeExpired.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorForUnknownError(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("unknown_error"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil {
|
||||
t.Fatalf("failed to get error")
|
||||
}
|
||||
if err != ErrDeviceGeneric {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceGeneric.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfTokenEmptyAndStatusOK(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrOAuthTokenEmpty {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrOAuthTokenEmpty.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
171
vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go
generated
vendored
171
vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go
generated
vendored
|
|
@ -1,171 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const MockTokenJSON string = `{
|
||||
"access_token": "accessToken",
|
||||
"refresh_token": "refreshToken",
|
||||
"expires_in": "1000",
|
||||
"expires_on": "2000",
|
||||
"not_before": "3000",
|
||||
"resource": "resource",
|
||||
"token_type": "type"
|
||||
}`
|
||||
|
||||
var TestToken = Token{
|
||||
AccessToken: "accessToken",
|
||||
RefreshToken: "refreshToken",
|
||||
ExpiresIn: "1000",
|
||||
ExpiresOn: "2000",
|
||||
NotBefore: "3000",
|
||||
Resource: "resource",
|
||||
Type: "type",
|
||||
}
|
||||
|
||||
func writeTestTokenFile(t *testing.T, suffix string, contents string) *os.File {
|
||||
f, err := ioutil.TempFile(os.TempDir(), suffix)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when creating temp file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write([]byte(contents))
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when writing temp test file: %v", err)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func TestLoadToken(t *testing.T) {
|
||||
f := writeTestTokenFile(t, "testloadtoken", MockTokenJSON)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
expectedToken := TestToken
|
||||
actualToken, err := LoadToken(f.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error loading token from file: %v", err)
|
||||
}
|
||||
|
||||
if *actualToken != expectedToken {
|
||||
t.Fatalf("azure: failed to decode properly expected(%v) actual(%v)", expectedToken, *actualToken)
|
||||
}
|
||||
|
||||
// test that LoadToken closes the file properly
|
||||
err = SaveToken(f.Name(), 0600, *actualToken)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: could not save token after LoadToken: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTokenFailsBadPath(t *testing.T) {
|
||||
_, err := LoadToken("/tmp/this_file_should_never_exist_really")
|
||||
expectedSubstring := "failed to open file"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTokenFailsBadJson(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockTokenJSON, "expires_on", ";:\"gibberish", -1)
|
||||
f := writeTestTokenFile(t, "testloadtokenfailsbadjson", gibberishJSON)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err := LoadToken(f.Name())
|
||||
expectedSubstring := "failed to decode contents of file"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func token() *Token {
|
||||
var token Token
|
||||
json.Unmarshal([]byte(MockTokenJSON), &token)
|
||||
return &token
|
||||
}
|
||||
|
||||
func TestSaveToken(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "testloadtoken")
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when creating temp file: %v", err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
f.Close()
|
||||
|
||||
mode := os.ModePerm & 0642
|
||||
err = SaveToken(f.Name(), mode, *token())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error saving token to file: %v", err)
|
||||
}
|
||||
fi, err := os.Stat(f.Name()) // open a new stat as held ones are not fresh
|
||||
if err != nil {
|
||||
t.Fatalf("azure: stat failed: %v", err)
|
||||
}
|
||||
if runtime.GOOS != "windows" { // permissions don't work on Windows
|
||||
if perm := fi.Mode().Perm(); perm != mode {
|
||||
t.Fatalf("azure: wrong file perm. got:%s; expected:%s file :%s", perm, mode, f.Name())
|
||||
}
|
||||
}
|
||||
|
||||
var actualToken Token
|
||||
var expectedToken Token
|
||||
|
||||
json.Unmarshal([]byte(MockTokenJSON), expectedToken)
|
||||
|
||||
contents, err := ioutil.ReadFile(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal("!!")
|
||||
}
|
||||
json.Unmarshal(contents, actualToken)
|
||||
|
||||
if !reflect.DeepEqual(actualToken, expectedToken) {
|
||||
t.Fatal("azure: token was not serialized correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveTokenFailsNoPermission(t *testing.T) {
|
||||
pathWhereWeShouldntHavePermission := "/usr/thiswontwork/atall"
|
||||
if runtime.GOOS == "windows" {
|
||||
pathWhereWeShouldntHavePermission = path.Join(os.Getenv("windir"), "system32\\mytokendir\\mytoken")
|
||||
}
|
||||
err := SaveToken(pathWhereWeShouldntHavePermission, 0644, *token())
|
||||
expectedSubstring := "failed to create directory"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveTokenFailsCantCreate(t *testing.T) {
|
||||
tokenPath := "/thiswontwork"
|
||||
if runtime.GOOS == "windows" {
|
||||
tokenPath = path.Join(os.Getenv("windir"), "system32")
|
||||
}
|
||||
err := SaveToken(tokenPath, 0644, *token())
|
||||
expectedSubstring := "failed to create the temp file to write the token"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err)
|
||||
}
|
||||
}
|
||||
929
vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go
generated
vendored
929
vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go
generated
vendored
|
|
@ -1,929 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/date"
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFormData = "client_id=id&client_secret=secret&grant_type=client_credentials&resource=resource"
|
||||
defaultManualFormData = "client_id=id&grant_type=refresh_token&refresh_token=refreshtoken&resource=resource"
|
||||
)
|
||||
|
||||
func TestTokenExpires(t *testing.T) {
|
||||
tt := time.Now().Add(5 * time.Second)
|
||||
tk := newTokenExpiresAt(tt)
|
||||
|
||||
if tk.Expires().Equal(tt) {
|
||||
t.Fatalf("adal: Token#Expires miscalculated expiration time -- received %v, expected %v", tk.Expires(), tt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsExpired(t *testing.T) {
|
||||
tk := newTokenExpiresAt(time.Now().Add(-5 * time.Second))
|
||||
|
||||
if !tk.IsExpired() {
|
||||
t.Fatalf("adal: Token#IsExpired failed to mark a stale token as expired -- now %v, token expires at %v",
|
||||
time.Now().UTC(), tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsExpiredUninitialized(t *testing.T) {
|
||||
tk := &Token{}
|
||||
|
||||
if !tk.IsExpired() {
|
||||
t.Fatalf("adal: An uninitialized Token failed to mark itself as expired (expiration time %v)", tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsNoExpired(t *testing.T) {
|
||||
tk := newTokenExpiresAt(time.Now().Add(1000 * time.Second))
|
||||
|
||||
if tk.IsExpired() {
|
||||
t.Fatalf("adal: Token marked a fresh token as expired -- now %v, token expires at %v", time.Now().UTC(), tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenWillExpireIn(t *testing.T) {
|
||||
d := 5 * time.Second
|
||||
tk := newTokenExpiresIn(d)
|
||||
|
||||
if !tk.WillExpireIn(d) {
|
||||
t.Fatal("adal: Token#WillExpireIn mismeasured expiration time")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetAutoRefresh(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
if !spt.inner.AutoRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken did not default to automatic token refreshing")
|
||||
}
|
||||
|
||||
spt.SetAutoRefresh(false)
|
||||
if spt.inner.AutoRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetAutoRefresh did not disable automatic token refreshing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetRefreshWithin(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
if spt.inner.RefreshWithin != defaultRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken did not correctly set the default refresh interval")
|
||||
}
|
||||
|
||||
spt.SetRefreshWithin(2 * defaultRefresh)
|
||||
if spt.inner.RefreshWithin != 2*defaultRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetRefreshWithin did not set the refresh interval")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetSender(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := &http.Client{}
|
||||
spt.SetSender(c)
|
||||
if !reflect.DeepEqual(c, spt.sender) {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetSender did not set the sender")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshUsesPOST(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method)
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("the response was not closed!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenFromMSIRefreshUsesGET(t *testing.T) {
|
||||
resource := "https://resource"
|
||||
cb := func(token Token) error { return nil }
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method != "GET" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "GET", r.Method)
|
||||
}
|
||||
if h := r.Header.Get("Metadata"); h != "true" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Metadata header for MSI")
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err = spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("the response was not closed!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenFromMSIRefreshCancel(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
endpoint, _ := GetMSIVMEndpoint()
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSI(endpoint, "https://resource")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.AppendAndRepeatResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError), 5)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
start := time.Now()
|
||||
end := time.Now()
|
||||
|
||||
go func() {
|
||||
spt.SetSender(c)
|
||||
err = spt.RefreshWithContext(ctx)
|
||||
end = time.Now()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
cancel()
|
||||
wg.Wait()
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
if end.Sub(start) >= time.Second {
|
||||
t.Fatalf("TestServicePrincipalTokenFromMSIRefreshCancel failed to cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshSetsMimeType(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Header.Get(http.CanonicalHeaderKey("Content-Type")) != "application/x-www-form-urlencoded" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Content-Type -- expected %v, received %v",
|
||||
"application/x-form-urlencoded",
|
||||
r.Header.Get(http.CanonicalHeaderKey("Content-Type")))
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshSetsURL(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.String() != TestOAuthConfig.TokenEndpoint.String() {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the URL -- expected %v, received %v",
|
||||
TestOAuthConfig.TokenEndpoint, r.URL)
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testServicePrincipalTokenRefreshSetsBody(t *testing.T, spt *ServicePrincipalToken, f func(*testing.T, []byte)) {
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("adal: Failed to read body of Service Principal token request (%v)", err)
|
||||
}
|
||||
f(t, b)
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenManualRefreshSetsBody(t *testing.T) {
|
||||
sptManual := newServicePrincipalTokenManual()
|
||||
testServicePrincipalTokenRefreshSetsBody(t, sptManual, func(t *testing.T, b []byte) {
|
||||
if string(b) != defaultManualFormData {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v",
|
||||
defaultManualFormData, string(b))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenCertficateRefreshSetsBody(t *testing.T) {
|
||||
sptCert := newServicePrincipalTokenCertificate(t)
|
||||
testServicePrincipalTokenRefreshSetsBody(t, sptCert, func(t *testing.T, b []byte) {
|
||||
body := string(b)
|
||||
|
||||
values, _ := url.ParseQuery(body)
|
||||
if values["client_assertion_type"][0] != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" ||
|
||||
values["client_id"][0] != "id" ||
|
||||
values["grant_type"][0] != "client_credentials" ||
|
||||
values["resource"][0] != "resource" {
|
||||
t.Fatalf("adal: ServicePrincipalTokenCertificate#Refresh did not correctly set the HTTP Request Body.")
|
||||
}
|
||||
|
||||
tok, _ := jwt.Parse(values["client_assertion"][0], nil)
|
||||
if tok == nil {
|
||||
t.Fatalf("adal: ServicePrincipalTokenCertificate#Expected client_assertion to be a JWT")
|
||||
}
|
||||
if _, ok := tok.Header["x5t"]; !ok {
|
||||
t.Fatalf("adal: ServicePrincipalTokenCertificate#Expected client_assertion to have an x5t header")
|
||||
}
|
||||
if _, ok := tok.Header["x5c"]; !ok {
|
||||
t.Fatalf("adal: ServicePrincipalTokenCertificate#Expected client_assertion to have an x5c header")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenUsernamePasswordRefreshSetsBody(t *testing.T) {
|
||||
spt := newServicePrincipalTokenUsernamePassword(t)
|
||||
testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) {
|
||||
body := string(b)
|
||||
|
||||
values, _ := url.ParseQuery(body)
|
||||
if values["client_id"][0] != "id" ||
|
||||
values["grant_type"][0] != "password" ||
|
||||
values["username"][0] != "username" ||
|
||||
values["password"][0] != "password" ||
|
||||
values["resource"][0] != "resource" {
|
||||
t.Fatalf("adal: ServicePrincipalTokenUsernamePassword#Refresh did not correctly set the HTTP Request Body.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenAuthorizationCodeRefreshSetsBody(t *testing.T) {
|
||||
spt := newServicePrincipalTokenAuthorizationCode(t)
|
||||
testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) {
|
||||
body := string(b)
|
||||
|
||||
values, _ := url.ParseQuery(body)
|
||||
if values["client_id"][0] != "id" ||
|
||||
values["grant_type"][0] != OAuthGrantTypeAuthorizationCode ||
|
||||
values["code"][0] != "code" ||
|
||||
values["client_secret"][0] != "clientSecret" ||
|
||||
values["redirect_uri"][0] != "http://redirectUri/getToken" ||
|
||||
values["resource"][0] != "resource" {
|
||||
t.Fatalf("adal: ServicePrincipalTokenAuthorizationCode#Refresh did not correctly set the HTTP Request Body.")
|
||||
}
|
||||
})
|
||||
testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) {
|
||||
body := string(b)
|
||||
|
||||
values, _ := url.ParseQuery(body)
|
||||
if values["client_id"][0] != "id" ||
|
||||
values["grant_type"][0] != OAuthGrantTypeRefreshToken ||
|
||||
values["code"][0] != "code" ||
|
||||
values["client_secret"][0] != "clientSecret" ||
|
||||
values["redirect_uri"][0] != "http://redirectUri/getToken" ||
|
||||
values["resource"][0] != "resource" {
|
||||
t.Fatalf("adal: ServicePrincipalTokenAuthorizationCode#Refresh did not correctly set the HTTP Request Body.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSecretRefreshSetsBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) {
|
||||
if string(b) != defaultFormData {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v",
|
||||
defaultFormData, string(b))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshClosesRequestBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if resp.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatal("adal: ServicePrincipalToken#Refresh failed to close the HTTP Response Body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshRejectsResponsesWithStatusNotOK(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusUnauthorized, "Unauthorized")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh should reject a response with status != %d", http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshRejectsEmptyBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return mocks.NewResponse(), nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatal("adal: ServicePrincipalToken#Refresh should reject an empty token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshPropagatesErrors(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.SetError(fmt.Errorf("Faux Error"))
|
||||
spt.SetSender(c)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatal("adal: Failed to propagate the request error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshReturnsErrorIfNotOk(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.AppendResponse(mocks.NewResponseWithStatus("401 NotAuthorized", http.StatusUnauthorized))
|
||||
spt.SetSender(c)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: Failed to return an when receiving a status code other than HTTP %d", http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshUnmarshals(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
resp := mocks.NewResponseWithContent(j)
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
} else if spt.inner.Token.AccessToken != "accessToken" ||
|
||||
spt.inner.Token.ExpiresIn != "3600" ||
|
||||
spt.inner.Token.ExpiresOn != json.Number(expiresOn) ||
|
||||
spt.inner.Token.NotBefore != json.Number(expiresOn) ||
|
||||
spt.inner.Token.Resource != "resource" ||
|
||||
spt.inner.Token.Type != "Bearer" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh failed correctly unmarshal the JSON -- expected %v, received %v",
|
||||
j, *spt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
expireToken(&spt.inner.Token)
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
f := false
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.EnsureFresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if !f {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh failed to call Refresh for stale token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenEnsureFreshFails(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
expireToken(&spt.inner.Token)
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.SetError(fmt.Errorf("some failure"))
|
||||
|
||||
spt.SetSender(c)
|
||||
err := spt.EnsureFresh()
|
||||
if err == nil {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh didn't return an error")
|
||||
}
|
||||
if _, ok := err.(TokenRefreshError); !ok {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh didn't return a TokenRefreshError")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenEnsureFreshSkipsIfFresh(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
setTokenToExpireIn(&spt.inner.Token, 1000*time.Second)
|
||||
|
||||
f := false
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return mocks.NewResponse(), nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.EnsureFresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if f {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh invoked Refresh for fresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshCallback(t *testing.T) {
|
||||
callbackTriggered := false
|
||||
spt := newServicePrincipalToken(func(Token) error {
|
||||
callbackTriggered = true
|
||||
return nil
|
||||
})
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
|
||||
sender := mocks.NewSender()
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(j))
|
||||
spt.SetSender(sender)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if !callbackTriggered {
|
||||
t.Fatalf("adal: RefreshCallback failed to trigger call callback")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshCallbackErrorPropagates(t *testing.T) {
|
||||
errorText := "this is an error text"
|
||||
spt := newServicePrincipalToken(func(Token) error {
|
||||
return fmt.Errorf(errorText)
|
||||
})
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
|
||||
sender := mocks.NewSender()
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(j))
|
||||
spt.SetSender(sender)
|
||||
err := spt.Refresh()
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), errorText) {
|
||||
t.Fatalf("adal: RefreshCallback failed to propagate error")
|
||||
}
|
||||
}
|
||||
|
||||
// This demonstrates the danger of manual token without a refresh token
|
||||
func TestServicePrincipalTokenManualRefreshFailsWithoutRefresh(t *testing.T) {
|
||||
spt := newServicePrincipalTokenManual()
|
||||
spt.inner.Token.RefreshToken = ""
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh should have failed with a ManualTokenSecret without a refresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServicePrincipalTokenFromMSI(t *testing.T) {
|
||||
resource := "https://resource"
|
||||
cb := func(token Token) error { return nil }
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
// check some of the SPT fields
|
||||
if _, ok := spt.inner.Secret.(*ServicePrincipalMSISecret); !ok {
|
||||
t.Fatal("SPT secret was not of MSI type")
|
||||
}
|
||||
|
||||
if spt.inner.Resource != resource {
|
||||
t.Fatal("SPT came back with incorrect resource")
|
||||
}
|
||||
|
||||
if len(spt.refreshCallbacks) != 1 {
|
||||
t.Fatal("SPT had incorrect refresh callbacks.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServicePrincipalTokenFromMSIWithUserAssignedID(t *testing.T) {
|
||||
resource := "https://resource"
|
||||
userID := "abc123"
|
||||
cb := func(token Token) error { return nil }
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSIWithUserAssignedID("http://msiendpoint/", resource, userID, cb)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
// check some of the SPT fields
|
||||
if _, ok := spt.inner.Secret.(*ServicePrincipalMSISecret); !ok {
|
||||
t.Fatal("SPT secret was not of MSI type")
|
||||
}
|
||||
|
||||
if spt.inner.Resource != resource {
|
||||
t.Fatal("SPT came back with incorrect resource")
|
||||
}
|
||||
|
||||
if len(spt.refreshCallbacks) != 1 {
|
||||
t.Fatal("SPT had incorrect refresh callbacks.")
|
||||
}
|
||||
|
||||
if spt.inner.ClientID != userID {
|
||||
t.Fatal("SPT had incorrect client ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServicePrincipalTokenFromManualTokenSecret(t *testing.T) {
|
||||
token := newToken()
|
||||
secret := &ServicePrincipalAuthorizationCodeSecret{
|
||||
ClientSecret: "clientSecret",
|
||||
AuthorizationCode: "code123",
|
||||
RedirectURI: "redirect",
|
||||
}
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromManualTokenSecret(TestOAuthConfig, "id", "resource", token, secret, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating new SPT: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(token, spt.inner.Token) {
|
||||
t.Fatalf("Tokens do not match: %s, %s", token, spt.inner.Token)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(secret, spt.inner.Secret) {
|
||||
t.Fatalf("Secrets do not match: %s, %s", secret, spt.inner.Secret)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetVMEndpoint(t *testing.T) {
|
||||
endpoint, err := GetMSIVMEndpoint()
|
||||
if err != nil {
|
||||
t.Fatal("Coudn't get VM endpoint")
|
||||
}
|
||||
|
||||
if endpoint != msiEndpoint {
|
||||
t.Fatal("Didn't get correct endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalNoSecret(t *testing.T) {
|
||||
spt := newServicePrincipalTokenManual()
|
||||
b, err := json.Marshal(spt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal token: %+v", err)
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal token: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(spt, spt2) {
|
||||
t.Fatal("tokens don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalTokenSecret(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
b, err := json.Marshal(spt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal token: %+v", err)
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal token: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(spt, spt2) {
|
||||
t.Fatal("tokens don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalCertificateSecret(t *testing.T) {
|
||||
spt := newServicePrincipalTokenCertificate(t)
|
||||
b, err := json.Marshal(spt)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when marshalling certificate token")
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when unmarshalling certificate token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalMSISecret(t *testing.T) {
|
||||
spt, err := newServicePrincipalTokenFromMSI("http://msiendpoint/", "https://resource", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get MSI SPT: %+v", err)
|
||||
}
|
||||
b, err := json.Marshal(spt)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when marshalling MSI token")
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when unmarshalling MSI token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalUsernamePasswordSecret(t *testing.T) {
|
||||
spt := newServicePrincipalTokenUsernamePassword(t)
|
||||
b, err := json.Marshal(spt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal token: %+v", err)
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal token: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(spt, spt2) {
|
||||
t.Fatal("tokens don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalServicePrincipalAuthorizationCodeSecret(t *testing.T) {
|
||||
spt := newServicePrincipalTokenAuthorizationCode(t)
|
||||
b, err := json.Marshal(spt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal token: %+v", err)
|
||||
}
|
||||
var spt2 *ServicePrincipalToken
|
||||
err = json.Unmarshal(b, &spt2)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal token: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(spt, spt2) {
|
||||
t.Fatal("tokens don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalInnerToken(t *testing.T) {
|
||||
spt := newServicePrincipalTokenManual()
|
||||
tokenJSON, err := spt.MarshalTokenJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal token: %+v", err)
|
||||
}
|
||||
|
||||
testToken := newToken()
|
||||
testToken.RefreshToken = "refreshtoken"
|
||||
|
||||
testTokenJSON, err := json.Marshal(testToken)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal test token: %+v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tokenJSON, testTokenJSON) {
|
||||
t.Fatalf("tokens don't match: %s, %s", tokenJSON, testTokenJSON)
|
||||
}
|
||||
|
||||
var t1 Token
|
||||
err = json.Unmarshal(tokenJSON, &t1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal token: %+v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(t1, testToken) {
|
||||
t.Fatalf("tokens don't match: %s, %s", t1, testToken)
|
||||
}
|
||||
}
|
||||
|
||||
func newTokenJSON(expiresOn string, resource string) string {
|
||||
return fmt.Sprintf(`{
|
||||
"access_token" : "accessToken",
|
||||
"expires_in" : "3600",
|
||||
"expires_on" : "%s",
|
||||
"not_before" : "%s",
|
||||
"resource" : "%s",
|
||||
"token_type" : "Bearer",
|
||||
"refresh_token": "ABC123"
|
||||
}`,
|
||||
expiresOn, expiresOn, resource)
|
||||
}
|
||||
|
||||
func newTokenExpiresIn(expireIn time.Duration) *Token {
|
||||
t := newToken()
|
||||
return setTokenToExpireIn(&t, expireIn)
|
||||
}
|
||||
|
||||
func newTokenExpiresAt(expireAt time.Time) *Token {
|
||||
t := newToken()
|
||||
return setTokenToExpireAt(&t, expireAt)
|
||||
}
|
||||
|
||||
func expireToken(t *Token) *Token {
|
||||
return setTokenToExpireIn(t, 0)
|
||||
}
|
||||
|
||||
func setTokenToExpireAt(t *Token, expireAt time.Time) *Token {
|
||||
t.ExpiresIn = "3600"
|
||||
t.ExpiresOn = json.Number(strconv.FormatInt(int64(expireAt.Sub(date.UnixEpoch())/time.Second), 10))
|
||||
t.NotBefore = t.ExpiresOn
|
||||
return t
|
||||
}
|
||||
|
||||
func setTokenToExpireIn(t *Token, expireIn time.Duration) *Token {
|
||||
return setTokenToExpireAt(t, time.Now().Add(expireIn))
|
||||
}
|
||||
|
||||
func newServicePrincipalToken(callbacks ...TokenRefreshCallback) *ServicePrincipalToken {
|
||||
spt, _ := NewServicePrincipalToken(TestOAuthConfig, "id", "secret", "resource", callbacks...)
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenManual() *ServicePrincipalToken {
|
||||
token := newToken()
|
||||
token.RefreshToken = "refreshtoken"
|
||||
spt, _ := NewServicePrincipalTokenFromManualToken(TestOAuthConfig, "id", "resource", token)
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenCertificate(t *testing.T) *ServicePrincipalToken {
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(0),
|
||||
Subject: pkix.Name{CommonName: "test"},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certificate, err := x509.ParseCertificate(certificateBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
spt, _ := NewServicePrincipalTokenFromCertificate(TestOAuthConfig, "id", certificate, privateKey, "resource")
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenUsernamePassword(t *testing.T) *ServicePrincipalToken {
|
||||
spt, _ := NewServicePrincipalTokenFromUsernamePassword(TestOAuthConfig, "id", "username", "password", "resource")
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenAuthorizationCode(t *testing.T) *ServicePrincipalToken {
|
||||
spt, _ := NewServicePrincipalTokenFromAuthorizationCode(TestOAuthConfig, "id", "clientSecret", "code", "http://redirectUri/getToken", "resource")
|
||||
return spt
|
||||
}
|
||||
230
vendor/github.com/Azure/go-autorest/autorest/authorization_test.go
generated
vendored
230
vendor/github.com/Azure/go-autorest/autorest/authorization_test.go
generated
vendored
|
|
@ -1,230 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
TestTenantID = "TestTenantID"
|
||||
TestActiveDirectoryEndpoint = "https://login/test.com/"
|
||||
)
|
||||
|
||||
func TestWithAuthorizer(t *testing.T) {
|
||||
r1 := mocks.NewRequest()
|
||||
|
||||
na := &NullAuthorizer{}
|
||||
r2, err := Prepare(r1,
|
||||
na.WithAuthorization())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: NullAuthorizer#WithAuthorization returned an unexpected error (%v)", err)
|
||||
} else if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatalf("autorest: NullAuthorizer#WithAuthorization modified the request -- received %v, expected %v", r2, r1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenWithAuthorization(t *testing.T) {
|
||||
token := &adal.Token{
|
||||
AccessToken: "TestToken",
|
||||
Resource: "https://azure.microsoft.com/",
|
||||
Type: "Bearer",
|
||||
}
|
||||
|
||||
ba := NewBearerAuthorizer(token)
|
||||
req, err := Prepare(&http.Request{}, ba.WithAuthorization())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", token.AccessToken) {
|
||||
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenWithAuthorizationNoRefresh(t *testing.T) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
spt.SetAutoRefresh(false)
|
||||
s := mocks.NewSender()
|
||||
spt.SetSender(s)
|
||||
|
||||
ba := NewBearerAuthorizer(spt)
|
||||
req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
|
||||
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) {
|
||||
|
||||
oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
refreshed := false
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", func(t adal.Token) error {
|
||||
refreshed = true
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
|
||||
jwt := `{
|
||||
"access_token" : "accessToken",
|
||||
"expires_in" : "3600",
|
||||
"expires_on" : "test",
|
||||
"not_before" : "test",
|
||||
"resource" : "test",
|
||||
"token_type" : "Bearer"
|
||||
}`
|
||||
body := mocks.NewBody(jwt)
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
|
||||
ba := NewBearerAuthorizer(spt)
|
||||
req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
|
||||
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
|
||||
}
|
||||
|
||||
if !refreshed {
|
||||
t.Fatal("azure: BearerAuthorizer#WithAuthorization must refresh the token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenWithAuthorizationReturnsErrorIfConnotRefresh(t *testing.T) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
}
|
||||
|
||||
s := mocks.NewSender()
|
||||
s.AppendResponse(mocks.NewResponseWithStatus("400 Bad Request", http.StatusBadRequest))
|
||||
spt.SetSender(s)
|
||||
|
||||
ba := NewBearerAuthorizer(spt)
|
||||
_, err = Prepare(mocks.NewRequest(), ba.WithAuthorization())
|
||||
if err == nil {
|
||||
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to return an error when refresh fails")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBearerAuthorizerCallback(t *testing.T) {
|
||||
tenantString := "123-tenantID-456"
|
||||
resourceString := "https://fake.resource.net"
|
||||
|
||||
s := mocks.NewSender()
|
||||
resp := mocks.NewResponseWithStatus("401 Unauthorized", http.StatusUnauthorized)
|
||||
mocks.SetResponseHeader(resp, bearerChallengeHeader, bearer+" \"authorization\"=\"https://fake.net/"+tenantString+"\",\"resource\"=\""+resourceString+"\"")
|
||||
s.AppendResponse(resp)
|
||||
|
||||
auth := NewBearerAuthorizerCallback(s, func(tenantID, resource string) (*BearerAuthorizer, error) {
|
||||
if tenantID != tenantString {
|
||||
t.Fatal("BearerAuthorizerCallback: bad tenant ID")
|
||||
}
|
||||
if resource != resourceString {
|
||||
t.Fatal("BearerAuthorizerCallback: bad resource")
|
||||
}
|
||||
|
||||
oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, tenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: NewOAuthConfig returned an error (%v)", err)
|
||||
}
|
||||
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", resource)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: NewServicePrincipalToken returned an error (%v)", err)
|
||||
}
|
||||
|
||||
spt.SetSender(s)
|
||||
return NewBearerAuthorizer(spt), nil
|
||||
})
|
||||
|
||||
_, err := Prepare(mocks.NewRequest(), auth.WithAuthorization())
|
||||
if err == nil {
|
||||
t.Fatal("azure: BearerAuthorizerCallback#WithAuthorization failed to return an error when refresh fails")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiKeyAuthorization(t *testing.T) {
|
||||
|
||||
headers := make(map[string]interface{})
|
||||
queryParameters := make(map[string]interface{})
|
||||
|
||||
dummyAuthHeader := "dummyAuthHeader"
|
||||
dummyAuthHeaderValue := "dummyAuthHeaderValue"
|
||||
|
||||
dummyAuthQueryParameter := "dummyAuthQueryParameter"
|
||||
dummyAuthQueryParameterValue := "dummyAuthQueryParameterValue"
|
||||
|
||||
headers[dummyAuthHeader] = dummyAuthHeaderValue
|
||||
queryParameters[dummyAuthQueryParameter] = dummyAuthQueryParameterValue
|
||||
|
||||
aka := NewAPIKeyAuthorizer(headers, queryParameters)
|
||||
|
||||
req, err := Prepare(mocks.NewRequest(), aka.WithAuthorization())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey(dummyAuthHeader)) != dummyAuthHeaderValue {
|
||||
t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s header", dummyAuthHeader)
|
||||
|
||||
} else if req.URL.Query().Get(dummyAuthQueryParameter) != dummyAuthQueryParameterValue {
|
||||
t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s query parameter", dummyAuthQueryParameterValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCognitivesServicesAuthorization(t *testing.T) {
|
||||
subscriptionKey := "dummyKey"
|
||||
csa := NewCognitiveServicesAuthorizer(subscriptionKey)
|
||||
req, err := Prepare(mocks.NewRequest(), csa.WithAuthorization())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization returned an error (%v)", err)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey(bingAPISdkHeader)) != golangBingAPISdkHeaderValue {
|
||||
t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", bingAPISdkHeader)
|
||||
} else if req.Header.Get(http.CanonicalHeaderKey(apiKeyAuthorizerHeader)) != subscriptionKey {
|
||||
t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", apiKeyAuthorizerHeader)
|
||||
}
|
||||
}
|
||||
140
vendor/github.com/Azure/go-autorest/autorest/autorest_test.go
generated
vendored
140
vendor/github.com/Azure/go-autorest/autorest/autorest_test.go
generated
vendored
|
|
@ -1,140 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
func TestResponseHasStatusCode(t *testing.T) {
|
||||
codes := []int{http.StatusOK, http.StatusAccepted}
|
||||
resp := &http.Response{StatusCode: http.StatusAccepted}
|
||||
if !ResponseHasStatusCode(resp, codes...) {
|
||||
t.Fatalf("autorest: ResponseHasStatusCode failed to find %v in %v", resp.StatusCode, codes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseHasStatusCodeNotPresent(t *testing.T) {
|
||||
codes := []int{http.StatusOK, http.StatusAccepted}
|
||||
resp := &http.Response{StatusCode: http.StatusInternalServerError}
|
||||
if ResponseHasStatusCode(resp, codes...) {
|
||||
t.Fatalf("autorest: ResponseHasStatusCode unexpectedly found %v in %v", resp.StatusCode, codes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPollingRequestDoesNotReturnARequestWhenLocationHeaderIsMissing(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("500 InternalServerError", http.StatusInternalServerError)
|
||||
|
||||
req, _ := NewPollingRequest(resp, nil)
|
||||
if req != nil {
|
||||
t.Fatal("autorest: NewPollingRequest returned an http.Request when the Location header was missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPollingRequestReturnsAnErrorWhenPrepareFails(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
resp.Header.Set(http.CanonicalHeaderKey(HeaderLocation), mocks.TestBadURL)
|
||||
|
||||
_, err := NewPollingRequest(resp, nil)
|
||||
if err == nil {
|
||||
t.Fatal("autorest: NewPollingRequest failed to return an error when Prepare fails")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPollingRequestDoesNotReturnARequestWhenPrepareFails(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
resp.Header.Set(http.CanonicalHeaderKey(HeaderLocation), mocks.TestBadURL)
|
||||
|
||||
req, _ := NewPollingRequest(resp, nil)
|
||||
if req != nil {
|
||||
t.Fatal("autorest: NewPollingRequest returned an http.Request when Prepare failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPollingRequestReturnsAGetRequest(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
|
||||
req, _ := NewPollingRequest(resp, nil)
|
||||
if req.Method != "GET" {
|
||||
t.Fatalf("autorest: NewPollingRequest did not create an HTTP GET request -- actual method %v", req.Method)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPollingRequestProvidesTheURL(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
|
||||
req, _ := NewPollingRequest(resp, nil)
|
||||
if req.URL.String() != mocks.TestURL {
|
||||
t.Fatalf("autorest: NewPollingRequest did not create an HTTP with the expected URL -- received %v, expected %v", req.URL, mocks.TestURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLocation(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
|
||||
l := GetLocation(resp)
|
||||
if len(l) == 0 {
|
||||
t.Fatalf("autorest: GetLocation failed to return Location header -- expected %v, received %v", mocks.TestURL, l)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLocationReturnsEmptyStringForMissingLocation(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
|
||||
l := GetLocation(resp)
|
||||
if len(l) != 0 {
|
||||
t.Fatalf("autorest: GetLocation return a value without a Location header -- received %v", l)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRetryAfter(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
|
||||
d := GetRetryAfter(resp, DefaultPollingDelay)
|
||||
if d != mocks.TestDelay {
|
||||
t.Fatalf("autorest: GetRetryAfter failed to returned the expected delay -- expected %v, received %v", mocks.TestDelay, d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRetryAfterReturnsDefaultDelayIfRetryHeaderIsMissing(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
|
||||
d := GetRetryAfter(resp, DefaultPollingDelay)
|
||||
if d != DefaultPollingDelay {
|
||||
t.Fatalf("autorest: GetRetryAfter failed to returned the default delay for a missing Retry-After header -- expected %v, received %v",
|
||||
DefaultPollingDelay, d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRetryAfterReturnsDefaultDelayIfRetryHeaderIsMalformed(t *testing.T) {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
resp.Header.Set(http.CanonicalHeaderKey(HeaderRetryAfter), "a very bad non-integer value")
|
||||
|
||||
d := GetRetryAfter(resp, DefaultPollingDelay)
|
||||
if d != DefaultPollingDelay {
|
||||
t.Fatalf("autorest: GetRetryAfter failed to returned the default delay for a malformed Retry-After header -- expected %v, received %v",
|
||||
DefaultPollingDelay, d)
|
||||
}
|
||||
}
|
||||
1156
vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go
generated
vendored
1156
vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
668
vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go
generated
vendored
668
vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go
generated
vendored
|
|
@ -1,668 +0,0 @@
|
|||
package azure
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
headerAuthorization = "Authorization"
|
||||
longDelay = 5 * time.Second
|
||||
retryDelay = 10 * time.Millisecond
|
||||
testLogPrefix = "azure:"
|
||||
)
|
||||
|
||||
// Use a Client Inspector to set the request identifier.
|
||||
func ExampleWithClientID() {
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
req, _ := autorest.Prepare(&http.Request{},
|
||||
autorest.AsGet(),
|
||||
autorest.WithBaseURL("https://microsoft.com/a/b/c/"))
|
||||
|
||||
c := autorest.Client{Sender: mocks.NewSender()}
|
||||
c.RequestInspector = WithReturningClientID(uuid)
|
||||
|
||||
autorest.SendWithSender(c, req)
|
||||
fmt.Printf("Inspector added the %s header with the value %s\n",
|
||||
HeaderClientID, req.Header.Get(HeaderClientID))
|
||||
fmt.Printf("Inspector added the %s header with the value %s\n",
|
||||
HeaderReturnClientID, req.Header.Get(HeaderReturnClientID))
|
||||
// Output:
|
||||
// Inspector added the x-ms-client-request-id header with the value 71FDB9F4-5E49-4C12-B266-DE7B4FD999A6
|
||||
// Inspector added the x-ms-return-client-request-id header with the value true
|
||||
}
|
||||
|
||||
func TestWithReturningClientIDReturnsError(t *testing.T) {
|
||||
var errIn error
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
_, errOut := autorest.Prepare(&http.Request{},
|
||||
withErrorPrepareDecorator(&errIn),
|
||||
WithReturningClientID(uuid))
|
||||
|
||||
if errOut == nil || errIn != errOut {
|
||||
t.Fatalf("azure: WithReturningClientID failed to exit early when receiving an error -- expected (%v), received (%v)",
|
||||
errIn, errOut)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithClientID(t *testing.T) {
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
req, _ := autorest.Prepare(&http.Request{},
|
||||
WithClientID(uuid))
|
||||
|
||||
if req.Header.Get(HeaderClientID) != uuid {
|
||||
t.Fatalf("azure: WithClientID failed to set %s -- expected %s, received %s",
|
||||
HeaderClientID, uuid, req.Header.Get(HeaderClientID))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithReturnClientID(t *testing.T) {
|
||||
b := false
|
||||
req, _ := autorest.Prepare(&http.Request{},
|
||||
WithReturnClientID(b))
|
||||
|
||||
if req.Header.Get(HeaderReturnClientID) != strconv.FormatBool(b) {
|
||||
t.Fatalf("azure: WithReturnClientID failed to set %s -- expected %s, received %s",
|
||||
HeaderClientID, strconv.FormatBool(b), req.Header.Get(HeaderClientID))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractClientID(t *testing.T) {
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
resp := mocks.NewResponse()
|
||||
mocks.SetResponseHeader(resp, HeaderClientID, uuid)
|
||||
|
||||
if ExtractClientID(resp) != uuid {
|
||||
t.Fatalf("azure: ExtractClientID failed to extract the %s -- expected %s, received %s",
|
||||
HeaderClientID, uuid, ExtractClientID(resp))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractRequestID(t *testing.T) {
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
resp := mocks.NewResponse()
|
||||
mocks.SetResponseHeader(resp, HeaderRequestID, uuid)
|
||||
|
||||
if ExtractRequestID(resp) != uuid {
|
||||
t.Fatalf("azure: ExtractRequestID failed to extract the %s -- expected %s, received %s",
|
||||
HeaderRequestID, uuid, ExtractRequestID(resp))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAzureError_ReturnsTrueForAzureError(t *testing.T) {
|
||||
if !IsAzureError(&RequestError{}) {
|
||||
t.Fatalf("azure: IsAzureError failed to return true for an Azure Service error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAzureError_ReturnsFalseForNonAzureError(t *testing.T) {
|
||||
if IsAzureError(fmt.Errorf("An Error")) {
|
||||
t.Fatalf("azure: IsAzureError return true for an non-Azure Service error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_UsesReponseStatusCode(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("Error"), "packageType", "method", mocks.NewResponseWithStatus("Forbidden", http.StatusForbidden), "message")
|
||||
if e.StatusCode != http.StatusForbidden {
|
||||
t.Fatalf("azure: NewErrorWithError failed to use the Status Code of the passed Response -- expected %v, received %v", http.StatusForbidden, e.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_ReturnsUnwrappedError(t *testing.T) {
|
||||
e1 := RequestError{}
|
||||
e1.ServiceError = &ServiceError{Code: "42", Message: "A Message"}
|
||||
e1.StatusCode = 200
|
||||
e1.RequestID = "A RequestID"
|
||||
e2 := NewErrorWithError(&e1, "packageType", "method", nil, "message")
|
||||
|
||||
if !reflect.DeepEqual(e1, e2) {
|
||||
t.Fatalf("azure: NewErrorWithError wrapped an RequestError -- expected %T, received %T", e1, e2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_WrapsAnError(t *testing.T) {
|
||||
e1 := fmt.Errorf("Inner Error")
|
||||
var e2 interface{} = NewErrorWithError(e1, "packageType", "method", nil, "message")
|
||||
|
||||
if _, ok := e2.(RequestError); !ok {
|
||||
t.Fatalf("azure: NewErrorWithError failed to wrap a standard error -- received %T", e2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode_NotAnAzureError(t *testing.T) {
|
||||
body := `<html>
|
||||
<head>
|
||||
<title>IIS Error page</title>
|
||||
</head>
|
||||
<body>Some non-JSON error page</body>
|
||||
</html>`
|
||||
r := mocks.NewResponseWithContent(body)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusBadRequest
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
ok, _ := err.(*RequestError)
|
||||
if ok != nil {
|
||||
t.Fatalf("azure: azure.RequestError returned from malformed response: %v", err)
|
||||
}
|
||||
|
||||
// the error body should still be there
|
||||
defer r.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != body {
|
||||
t.Fatalf("response body is wrong. got=%q exptected=%q", string(b), body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode_FoundAzureErrorWithoutDetails(t *testing.T) {
|
||||
j := `{
|
||||
"error": {
|
||||
"code": "InternalError",
|
||||
"message": "Azure is having trouble right now."
|
||||
}
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: returned nil error for proper error response")
|
||||
}
|
||||
azErr, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
t.Fatalf("azure: returned error is not azure.RequestError: %T", err)
|
||||
}
|
||||
|
||||
expected := "autorest/azure: Service returned an error. Status=500 Code=\"InternalError\" Message=\"Azure is having trouble right now.\""
|
||||
if !reflect.DeepEqual(expected, azErr.Error()) {
|
||||
t.Fatalf("azure: service error is not unmarshaled properly.\nexpected=%v\ngot=%v", expected, azErr.Error())
|
||||
}
|
||||
|
||||
if expected := http.StatusInternalServerError; azErr.StatusCode != expected {
|
||||
t.Fatalf("azure: got wrong StatusCode=%d Expected=%d", azErr.StatusCode, expected)
|
||||
}
|
||||
if expected := uuid; azErr.RequestID != expected {
|
||||
t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID)
|
||||
}
|
||||
|
||||
_ = azErr.Error()
|
||||
|
||||
// the error body should still be there
|
||||
defer r.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != j {
|
||||
t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode_FoundAzureFullError(t *testing.T) {
|
||||
j := `{
|
||||
"error": {
|
||||
"code": "InternalError",
|
||||
"message": "Azure is having trouble right now.",
|
||||
"target": "target1",
|
||||
"details": [{"code": "conflict1", "message":"error message1"},
|
||||
{"code": "conflict2", "message":"error message2"}],
|
||||
"innererror": { "customKey": "customValue" },
|
||||
"additionalInfo": [{"type": "someErrorType", "info": {"someProperty": "someValue"}}]
|
||||
}
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: returned nil error for proper error response")
|
||||
}
|
||||
azErr, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
t.Fatalf("azure: returned error is not azure.RequestError: %T", err)
|
||||
}
|
||||
|
||||
if expected := "InternalError"; azErr.ServiceError.Code != expected {
|
||||
t.Fatalf("azure: wrong error code. expected=%q; got=%q", expected, azErr.ServiceError.Code)
|
||||
}
|
||||
|
||||
if azErr.ServiceError.Message == "" {
|
||||
t.Fatalf("azure: error message is not unmarshaled properly")
|
||||
}
|
||||
|
||||
if *azErr.ServiceError.Target == "" {
|
||||
t.Fatalf("azure: error target is not unmarshaled properly")
|
||||
}
|
||||
|
||||
d, _ := json.Marshal(azErr.ServiceError.Details)
|
||||
if string(d) != `[{"code":"conflict1","message":"error message1"},{"code":"conflict2","message":"error message2"}]` {
|
||||
t.Fatalf("azure: error details is not unmarshaled properly")
|
||||
}
|
||||
|
||||
i, _ := json.Marshal(azErr.ServiceError.InnerError)
|
||||
if string(i) != `{"customKey":"customValue"}` {
|
||||
t.Fatalf("azure: inner error is not unmarshaled properly")
|
||||
}
|
||||
|
||||
a, _ := json.Marshal(azErr.ServiceError.AdditionalInfo)
|
||||
if string(a) != `[{"info":{"someProperty":"someValue"},"type":"someErrorType"}]` {
|
||||
t.Fatalf("azure: error additional info is not unmarshaled properly")
|
||||
}
|
||||
|
||||
if expected := http.StatusInternalServerError; azErr.StatusCode != expected {
|
||||
t.Fatalf("azure: got wrong StatusCode=%v Expected=%d", azErr.StatusCode, expected)
|
||||
}
|
||||
if expected := uuid; azErr.RequestID != expected {
|
||||
t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID)
|
||||
}
|
||||
|
||||
_ = azErr.Error()
|
||||
|
||||
// the error body should still be there
|
||||
defer r.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != j {
|
||||
t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode_NoAzureError(t *testing.T) {
|
||||
j := `{
|
||||
"Status":"NotFound"
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
if err == nil {
|
||||
t.Fatalf("azure: returned nil error for proper error response")
|
||||
}
|
||||
azErr, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
t.Fatalf("azure: returned error is not azure.RequestError: %T", err)
|
||||
}
|
||||
|
||||
expected := &ServiceError{
|
||||
Code: "Unknown",
|
||||
Message: "Unknown service error",
|
||||
Details: []map[string]interface{}{
|
||||
{"Status": "NotFound"},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, azErr.ServiceError) {
|
||||
t.Fatalf("azure: service error is not unmarshaled properly. expected=%q\ngot=%q", expected, azErr.ServiceError)
|
||||
}
|
||||
|
||||
if expected := http.StatusInternalServerError; azErr.StatusCode != expected {
|
||||
t.Fatalf("azure: got wrong StatusCode=%v Expected=%d", azErr.StatusCode, expected)
|
||||
}
|
||||
if expected := uuid; azErr.RequestID != expected {
|
||||
t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID)
|
||||
}
|
||||
|
||||
_ = azErr.Error()
|
||||
|
||||
// the error body should still be there
|
||||
defer r.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != j {
|
||||
t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode_UnwrappedError(t *testing.T) {
|
||||
j := `{
|
||||
"code": "InternalError",
|
||||
"message": "Azure is having trouble right now.",
|
||||
"target": "target1",
|
||||
"details": [{"code": "conflict1", "message":"error message1"},
|
||||
{"code": "conflict2", "message":"error message2"}],
|
||||
"innererror": { "customKey": "customValue" },
|
||||
"additionalInfo": [{"type": "someErrorType", "info": {"someProperty": "someValue"}}]
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("azure: returned nil error for proper error response")
|
||||
}
|
||||
|
||||
azErr, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
t.Fatalf("returned error is not azure.RequestError: %T", err)
|
||||
}
|
||||
|
||||
if expected := http.StatusInternalServerError; azErr.StatusCode != expected {
|
||||
t.Logf("Incorrect StatusCode got: %v want: %d", azErr.StatusCode, expected)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if expected := "Azure is having trouble right now."; azErr.Message != expected {
|
||||
t.Logf("Incorrect Message\n\tgot: %q\n\twant: %q", azErr.Message, expected)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if expected := uuid; azErr.RequestID != expected {
|
||||
t.Logf("Incorrect request ID\n\tgot: %q\n\twant: %q", azErr.RequestID, expected)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if azErr.ServiceError == nil {
|
||||
t.Logf("`ServiceError` was nil when it shouldn't have been.")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if expected := "target1"; *azErr.ServiceError.Target != expected {
|
||||
t.Logf("Incorrect Target\n\tgot: %q\n\twant: %q", *azErr.ServiceError.Target, expected)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
expectedServiceErrorDetails := `[{"code":"conflict1","message":"error message1"},{"code":"conflict2","message":"error message2"}]`
|
||||
if azErr.ServiceError.Details == nil {
|
||||
t.Logf("`ServiceError.Details` was nil when it should have been %q", expectedServiceErrorDetails)
|
||||
t.Fail()
|
||||
} else if details, _ := json.Marshal(azErr.ServiceError.Details); expectedServiceErrorDetails != string(details) {
|
||||
t.Logf("Error details was not unmarshaled properly.\n\tgot: %q\n\twant: %q", string(details), expectedServiceErrorDetails)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
expectedServiceErrorInnerError := `{"customKey":"customValue"}`
|
||||
if azErr.ServiceError.InnerError == nil {
|
||||
t.Logf("`ServiceError.InnerError` was nil when it should have been %q", expectedServiceErrorInnerError)
|
||||
t.Fail()
|
||||
} else if innerError, _ := json.Marshal(azErr.ServiceError.InnerError); expectedServiceErrorInnerError != string(innerError) {
|
||||
t.Logf("Inner error was not unmarshaled properly.\n\tgot: %q\n\twant: %q", string(innerError), expectedServiceErrorInnerError)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
expectedServiceErrorAdditionalInfo := `[{"info":{"someProperty":"someValue"},"type":"someErrorType"}]`
|
||||
if azErr.ServiceError.AdditionalInfo == nil {
|
||||
t.Logf("`ServiceError.AdditionalInfo` was nil when it should have been %q", expectedServiceErrorAdditionalInfo)
|
||||
t.Fail()
|
||||
} else if additionalInfo, _ := json.Marshal(azErr.ServiceError.AdditionalInfo); expectedServiceErrorAdditionalInfo != string(additionalInfo) {
|
||||
t.Logf("Additional info was not unmarshaled properly.\n\tgot: %q\n\twant: %q", string(additionalInfo), expectedServiceErrorAdditionalInfo)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// the error body should still be there
|
||||
defer r.Body.Close()
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if string(b) != j {
|
||||
t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRequestErrorString_WithError(t *testing.T) {
|
||||
j := `{
|
||||
"error": {
|
||||
"code": "InternalError",
|
||||
"message": "Conflict",
|
||||
"target": "target1",
|
||||
"details": [{"code": "conflict1", "message":"error message1"}],
|
||||
"innererror": { "customKey": "customValue" },
|
||||
"additionalInfo": [{"type": "someErrorType", "info": {"someProperty": "someValue"}}]
|
||||
}
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: returned nil error for proper error response")
|
||||
}
|
||||
azErr, _ := err.(*RequestError)
|
||||
expected := "autorest/azure: Service returned an error. Status=500 Code=\"InternalError\" Message=\"Conflict\" Target=\"target1\" Details=[{\"code\":\"conflict1\",\"message\":\"error message1\"}] InnerError={\"customKey\":\"customValue\"} AdditionalInfo=[{\"info\":{\"someProperty\":\"someValue\"},\"type\":\"someErrorType\"}]"
|
||||
if expected != azErr.Error() {
|
||||
t.Fatalf("azure: send wrong RequestError.\nexpected=%v\ngot=%v", expected, azErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestErrorString_WithErrorNonConforming(t *testing.T) {
|
||||
j := `{
|
||||
"error": {
|
||||
"code": "InternalError",
|
||||
"message": "Conflict",
|
||||
"details": {"code": "conflict1", "message":"error message1"}
|
||||
}
|
||||
}`
|
||||
uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6"
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
mocks.SetResponseHeader(r, HeaderRequestID, uuid)
|
||||
r.Request = mocks.NewRequest()
|
||||
r.StatusCode = http.StatusInternalServerError
|
||||
r.Status = http.StatusText(r.StatusCode)
|
||||
|
||||
err := autorest.Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
autorest.ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: returned nil error for proper error response")
|
||||
}
|
||||
azErr, _ := err.(*RequestError)
|
||||
expected := "autorest/azure: Service returned an error. Status=500 Code=\"InternalError\" Message=\"Conflict\" Details=[{\"code\":\"conflict1\",\"message\":\"error message1\"}]"
|
||||
if expected != azErr.Error() {
|
||||
t.Fatalf("azure: send wrong RequestError.\nexpected=%v\ngot=%v", expected, azErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResourceID_WithValidBasicResourceID(t *testing.T) {
|
||||
|
||||
basicResourceID := "/subscriptions/subid-3-3-4/resourceGroups/regGroupVladdb/providers/Microsoft.Network/LoadBalancer/testResourceName"
|
||||
want := Resource{
|
||||
SubscriptionID: "subid-3-3-4",
|
||||
ResourceGroup: "regGroupVladdb",
|
||||
Provider: "Microsoft.Network",
|
||||
ResourceType: "LoadBalancer",
|
||||
ResourceName: "testResourceName",
|
||||
}
|
||||
got, err := ParseResourceID(basicResourceID)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("azure: error returned while parsing valid resourceId")
|
||||
}
|
||||
|
||||
if got != want {
|
||||
t.Logf("got: %+v\nwant: %+v", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResourceID_WithValidSubResourceID(t *testing.T) {
|
||||
subresourceID := "/subscriptions/subid-3-3-4/resourceGroups/regGroupVladdb/providers/Microsoft.Network/LoadBalancer/resource/is/a/subresource/actualresourceName"
|
||||
want := Resource{
|
||||
SubscriptionID: "subid-3-3-4",
|
||||
ResourceGroup: "regGroupVladdb",
|
||||
Provider: "Microsoft.Network",
|
||||
ResourceType: "LoadBalancer",
|
||||
ResourceName: "actualresourceName",
|
||||
}
|
||||
got, err := ParseResourceID(subresourceID)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("azure: error returned while parsing valid resourceId")
|
||||
}
|
||||
|
||||
if got != want {
|
||||
t.Logf("got: %+v\nwant: %+v", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResourceID_WithIncompleteResourceID(t *testing.T) {
|
||||
basicResourceID := "/subscriptions/subid-3-3-4/resourceGroups/regGroupVladdb/providers/Microsoft.Network/"
|
||||
want := Resource{}
|
||||
|
||||
got, err := ParseResourceID(basicResourceID)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: no error returned on incomplete resource id")
|
||||
}
|
||||
|
||||
if got != want {
|
||||
t.Logf("got: %+v\nwant: %+v", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResourceID_WithMalformedResourceID(t *testing.T) {
|
||||
malformedResourceID := "/providers/subid-3-3-4/resourceGroups/regGroupVladdb/subscriptions/Microsoft.Network/LoadBalancer/testResourceName"
|
||||
want := Resource{}
|
||||
|
||||
got, err := ParseResourceID(malformedResourceID)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("azure: error returned while parsing malformed resourceID")
|
||||
}
|
||||
|
||||
if got != want {
|
||||
t.Logf("got: %+v\nwant: %+v", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func withErrorPrepareDecorator(e *error) autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
*e = fmt.Errorf("azure: Faux Prepare Error")
|
||||
return r, *e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func withAsyncResponseDecorator(n int) autorest.SendDecorator {
|
||||
i := 0
|
||||
return func(s autorest.Sender) autorest.Sender {
|
||||
return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err == nil {
|
||||
if i < n {
|
||||
resp.StatusCode = http.StatusCreated
|
||||
resp.Header = http.Header{}
|
||||
resp.Header.Add(http.CanonicalHeaderKey(headerAsyncOperation), mocks.TestURL)
|
||||
i++
|
||||
} else {
|
||||
resp.StatusCode = http.StatusOK
|
||||
resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation))
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockAuthorizer struct{}
|
||||
|
||||
func (ma mockAuthorizer) WithAuthorization() autorest.PrepareDecorator {
|
||||
return autorest.WithHeader(headerAuthorization, mocks.TestAuthorizationHeader)
|
||||
}
|
||||
|
||||
type mockFailingAuthorizer struct{}
|
||||
|
||||
func (mfa mockFailingAuthorizer) WithAuthorization() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockInspector struct {
|
||||
wasInvoked bool
|
||||
}
|
||||
|
||||
func (mi *mockInspector) WithInspection() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
mi.wasInvoked = true
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (mi *mockInspector) ByInspecting() autorest.RespondDecorator {
|
||||
return func(r autorest.Responder) autorest.Responder {
|
||||
return autorest.ResponderFunc(func(resp *http.Response) error {
|
||||
mi.wasInvoked = true
|
||||
return r.Respond(resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
348
vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go
generated
vendored
348
vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go
generated
vendored
|
|
@ -1,348 +0,0 @@
|
|||
// test
|
||||
package azure
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// This correlates to the expected contents of ./testdata/test_environment_1.json
|
||||
var testEnvironment1 = Environment{
|
||||
Name: "--unit-test--",
|
||||
ManagementPortalURL: "--management-portal-url",
|
||||
PublishSettingsURL: "--publish-settings-url--",
|
||||
ServiceManagementEndpoint: "--service-management-endpoint--",
|
||||
ResourceManagerEndpoint: "--resource-management-endpoint--",
|
||||
ActiveDirectoryEndpoint: "--active-directory-endpoint--",
|
||||
GalleryEndpoint: "--gallery-endpoint--",
|
||||
KeyVaultEndpoint: "--key-vault--endpoint--",
|
||||
GraphEndpoint: "--graph-endpoint--",
|
||||
StorageEndpointSuffix: "--storage-endpoint-suffix--",
|
||||
SQLDatabaseDNSSuffix: "--sql-database-dns-suffix--",
|
||||
TrafficManagerDNSSuffix: "--traffic-manager-dns-suffix--",
|
||||
KeyVaultDNSSuffix: "--key-vault-dns-suffix--",
|
||||
ServiceBusEndpointSuffix: "--service-bus-endpoint-suffix--",
|
||||
ServiceManagementVMDNSSuffix: "--asm-vm-dns-suffix--",
|
||||
ResourceManagerVMDNSSuffix: "--arm-vm-dns-suffix--",
|
||||
ContainerRegistryDNSSuffix: "--container-registry-dns-suffix--",
|
||||
TokenAudience: "--token-audience",
|
||||
}
|
||||
|
||||
func TestEnvironment_EnvironmentFromURL_NoOverride_Success(t *testing.T) {
|
||||
fileContents, _ := ioutil.ReadFile(filepath.Join("testdata", "test_metadata_environment_1.json"))
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(fileContents))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
got, err := EnvironmentFromURL(ts.URL)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got.Name != "HybridEnvironment" {
|
||||
t.Logf("got: %v want: HybridEnvironment", got.Name)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_EnvironmentFromURL_OverrideStorageSuffix_Success(t *testing.T) {
|
||||
fileContents, _ := ioutil.ReadFile(filepath.Join("testdata", "test_metadata_environment_1.json"))
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(fileContents))
|
||||
}))
|
||||
defer ts.Close()
|
||||
overrideProperty := OverrideProperty{
|
||||
Key: EnvironmentStorageEndpointSuffix,
|
||||
Value: "fakeStorageSuffix",
|
||||
}
|
||||
got, err := EnvironmentFromURL(ts.URL, overrideProperty)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got.StorageEndpointSuffix != "fakeStorageSuffix" {
|
||||
t.Logf("got: %v want: fakeStorageSuffix", got.StorageEndpointSuffix)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_EnvironmentFromURL_EmptyEndpoint_Failure(t *testing.T) {
|
||||
_, err := EnvironmentFromURL("")
|
||||
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
if err.Error() != "Metadata resource manager endpoint is empty" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_EnvironmentFromFile(t *testing.T) {
|
||||
got, err := EnvironmentFromFile(filepath.Join("testdata", "test_environment_1.json"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if got != testEnvironment1 {
|
||||
t.Logf("got: %v want: %v", got, testEnvironment1)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_EnvironmentFromName_Stack(t *testing.T) {
|
||||
_, currentFile, _, _ := runtime.Caller(0)
|
||||
prevEnvFilepathValue := os.Getenv(EnvironmentFilepathName)
|
||||
os.Setenv(EnvironmentFilepathName, filepath.Join(path.Dir(currentFile), "testdata", "test_environment_1.json"))
|
||||
defer os.Setenv(EnvironmentFilepathName, prevEnvFilepathValue)
|
||||
|
||||
got, err := EnvironmentFromName("AZURESTACKCLOUD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if got != testEnvironment1 {
|
||||
t.Logf("got: %v want: %v", got, testEnvironment1)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironmentFromName(t *testing.T) {
|
||||
name := "azurechinacloud"
|
||||
if env, _ := EnvironmentFromName(name); env != ChinaCloud {
|
||||
t.Errorf("Expected to get ChinaCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "AzureChinaCloud"
|
||||
if env, _ := EnvironmentFromName(name); env != ChinaCloud {
|
||||
t.Errorf("Expected to get ChinaCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "azuregermancloud"
|
||||
if env, _ := EnvironmentFromName(name); env != GermanCloud {
|
||||
t.Errorf("Expected to get GermanCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "AzureGermanCloud"
|
||||
if env, _ := EnvironmentFromName(name); env != GermanCloud {
|
||||
t.Errorf("Expected to get GermanCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "azurepubliccloud"
|
||||
if env, _ := EnvironmentFromName(name); env != PublicCloud {
|
||||
t.Errorf("Expected to get PublicCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "AzurePublicCloud"
|
||||
if env, _ := EnvironmentFromName(name); env != PublicCloud {
|
||||
t.Errorf("Expected to get PublicCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "azureusgovernmentcloud"
|
||||
if env, _ := EnvironmentFromName(name); env != USGovernmentCloud {
|
||||
t.Errorf("Expected to get USGovernmentCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "AzureUSGovernmentCloud"
|
||||
if env, _ := EnvironmentFromName(name); env != USGovernmentCloud {
|
||||
t.Errorf("Expected to get USGovernmentCloud for %q", name)
|
||||
}
|
||||
|
||||
name = "thisisnotarealcloudenv"
|
||||
if _, err := EnvironmentFromName(name); err == nil {
|
||||
t.Errorf("Expected to get an error for %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeserializeEnvironment(t *testing.T) {
|
||||
env := `{
|
||||
"name": "--name--",
|
||||
"ActiveDirectoryEndpoint": "--active-directory-endpoint--",
|
||||
"galleryEndpoint": "--gallery-endpoint--",
|
||||
"graphEndpoint": "--graph-endpoint--",
|
||||
"serviceBusEndpoint": "--service-bus-endpoint--",
|
||||
"keyVaultDNSSuffix": "--key-vault-dns-suffix--",
|
||||
"keyVaultEndpoint": "--key-vault-endpoint--",
|
||||
"managementPortalURL": "--management-portal-url--",
|
||||
"publishSettingsURL": "--publish-settings-url--",
|
||||
"resourceManagerEndpoint": "--resource-manager-endpoint--",
|
||||
"serviceBusEndpointSuffix": "--service-bus-endpoint-suffix--",
|
||||
"serviceManagementEndpoint": "--service-management-endpoint--",
|
||||
"sqlDatabaseDNSSuffix": "--sql-database-dns-suffix--",
|
||||
"storageEndpointSuffix": "--storage-endpoint-suffix--",
|
||||
"trafficManagerDNSSuffix": "--traffic-manager-dns-suffix--",
|
||||
"serviceManagementVMDNSSuffix": "--asm-vm-dns-suffix--",
|
||||
"resourceManagerVMDNSSuffix": "--arm-vm-dns-suffix--",
|
||||
"containerRegistryDNSSuffix": "--container-registry-dns-suffix--"
|
||||
}`
|
||||
|
||||
testSubject := Environment{}
|
||||
err := json.Unmarshal([]byte(env), &testSubject)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal: %s", err)
|
||||
}
|
||||
|
||||
if "--name--" != testSubject.Name {
|
||||
t.Errorf("Expected Name to be \"--name--\", but got %q", testSubject.Name)
|
||||
}
|
||||
if "--management-portal-url--" != testSubject.ManagementPortalURL {
|
||||
t.Errorf("Expected ManagementPortalURL to be \"--management-portal-url--\", but got %q", testSubject.ManagementPortalURL)
|
||||
}
|
||||
if "--publish-settings-url--" != testSubject.PublishSettingsURL {
|
||||
t.Errorf("Expected PublishSettingsURL to be \"--publish-settings-url--\", but got %q", testSubject.PublishSettingsURL)
|
||||
}
|
||||
if "--service-management-endpoint--" != testSubject.ServiceManagementEndpoint {
|
||||
t.Errorf("Expected ServiceManagementEndpoint to be \"--service-management-endpoint--\", but got %q", testSubject.ServiceManagementEndpoint)
|
||||
}
|
||||
if "--resource-manager-endpoint--" != testSubject.ResourceManagerEndpoint {
|
||||
t.Errorf("Expected ResourceManagerEndpoint to be \"--resource-manager-endpoint--\", but got %q", testSubject.ResourceManagerEndpoint)
|
||||
}
|
||||
if "--active-directory-endpoint--" != testSubject.ActiveDirectoryEndpoint {
|
||||
t.Errorf("Expected ActiveDirectoryEndpoint to be \"--active-directory-endpoint--\", but got %q", testSubject.ActiveDirectoryEndpoint)
|
||||
}
|
||||
if "--gallery-endpoint--" != testSubject.GalleryEndpoint {
|
||||
t.Errorf("Expected GalleryEndpoint to be \"--gallery-endpoint--\", but got %q", testSubject.GalleryEndpoint)
|
||||
}
|
||||
if "--key-vault-endpoint--" != testSubject.KeyVaultEndpoint {
|
||||
t.Errorf("Expected KeyVaultEndpoint to be \"--key-vault-endpoint--\", but got %q", testSubject.KeyVaultEndpoint)
|
||||
}
|
||||
if "--service-bus-endpoint--" != testSubject.ServiceBusEndpoint {
|
||||
t.Errorf("Expected ServiceBusEndpoint to be \"--service-bus-endpoint--\", but goet %q", testSubject.ServiceBusEndpoint)
|
||||
}
|
||||
if "--graph-endpoint--" != testSubject.GraphEndpoint {
|
||||
t.Errorf("Expected GraphEndpoint to be \"--graph-endpoint--\", but got %q", testSubject.GraphEndpoint)
|
||||
}
|
||||
if "--storage-endpoint-suffix--" != testSubject.StorageEndpointSuffix {
|
||||
t.Errorf("Expected StorageEndpointSuffix to be \"--storage-endpoint-suffix--\", but got %q", testSubject.StorageEndpointSuffix)
|
||||
}
|
||||
if "--sql-database-dns-suffix--" != testSubject.SQLDatabaseDNSSuffix {
|
||||
t.Errorf("Expected sql-database-dns-suffix to be \"--sql-database-dns-suffix--\", but got %q", testSubject.SQLDatabaseDNSSuffix)
|
||||
}
|
||||
if "--key-vault-dns-suffix--" != testSubject.KeyVaultDNSSuffix {
|
||||
t.Errorf("Expected StorageEndpointSuffix to be \"--key-vault-dns-suffix--\", but got %q", testSubject.KeyVaultDNSSuffix)
|
||||
}
|
||||
if "--service-bus-endpoint-suffix--" != testSubject.ServiceBusEndpointSuffix {
|
||||
t.Errorf("Expected StorageEndpointSuffix to be \"--service-bus-endpoint-suffix--\", but got %q", testSubject.ServiceBusEndpointSuffix)
|
||||
}
|
||||
if "--asm-vm-dns-suffix--" != testSubject.ServiceManagementVMDNSSuffix {
|
||||
t.Errorf("Expected ServiceManagementVMDNSSuffix to be \"--asm-vm-dns-suffix--\", but got %q", testSubject.ServiceManagementVMDNSSuffix)
|
||||
}
|
||||
if "--arm-vm-dns-suffix--" != testSubject.ResourceManagerVMDNSSuffix {
|
||||
t.Errorf("Expected ResourceManagerVMDNSSuffix to be \"--arm-vm-dns-suffix--\", but got %q", testSubject.ResourceManagerVMDNSSuffix)
|
||||
}
|
||||
if "--container-registry-dns-suffix--" != testSubject.ContainerRegistryDNSSuffix {
|
||||
t.Errorf("Expected ContainerRegistryDNSSuffix to be \"--container-registry-dns-suffix--\", but got %q", testSubject.ContainerRegistryDNSSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTripSerialization(t *testing.T) {
|
||||
env := Environment{
|
||||
Name: "--unit-test--",
|
||||
ManagementPortalURL: "--management-portal-url",
|
||||
PublishSettingsURL: "--publish-settings-url--",
|
||||
ServiceManagementEndpoint: "--service-management-endpoint--",
|
||||
ResourceManagerEndpoint: "--resource-management-endpoint--",
|
||||
ActiveDirectoryEndpoint: "--active-directory-endpoint--",
|
||||
GalleryEndpoint: "--gallery-endpoint--",
|
||||
KeyVaultEndpoint: "--key-vault--endpoint--",
|
||||
GraphEndpoint: "--graph-endpoint--",
|
||||
ServiceBusEndpoint: "--service-bus-endpoint--",
|
||||
StorageEndpointSuffix: "--storage-endpoint-suffix--",
|
||||
SQLDatabaseDNSSuffix: "--sql-database-dns-suffix--",
|
||||
TrafficManagerDNSSuffix: "--traffic-manager-dns-suffix--",
|
||||
KeyVaultDNSSuffix: "--key-vault-dns-suffix--",
|
||||
ServiceBusEndpointSuffix: "--service-bus-endpoint-suffix--",
|
||||
ServiceManagementVMDNSSuffix: "--asm-vm-dns-suffix--",
|
||||
ResourceManagerVMDNSSuffix: "--arm-vm-dns-suffix--",
|
||||
ContainerRegistryDNSSuffix: "--container-registry-dns-suffix--",
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(env)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal: %s", err)
|
||||
}
|
||||
|
||||
testSubject := Environment{}
|
||||
err = json.Unmarshal(bytes, &testSubject)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal: %s", err)
|
||||
}
|
||||
|
||||
if env.Name != testSubject.Name {
|
||||
t.Errorf("Expected Name to be %q, but got %q", env.Name, testSubject.Name)
|
||||
}
|
||||
if env.ManagementPortalURL != testSubject.ManagementPortalURL {
|
||||
t.Errorf("Expected ManagementPortalURL to be %q, but got %q", env.ManagementPortalURL, testSubject.ManagementPortalURL)
|
||||
}
|
||||
if env.PublishSettingsURL != testSubject.PublishSettingsURL {
|
||||
t.Errorf("Expected PublishSettingsURL to be %q, but got %q", env.PublishSettingsURL, testSubject.PublishSettingsURL)
|
||||
}
|
||||
if env.ServiceManagementEndpoint != testSubject.ServiceManagementEndpoint {
|
||||
t.Errorf("Expected ServiceManagementEndpoint to be %q, but got %q", env.ServiceManagementEndpoint, testSubject.ServiceManagementEndpoint)
|
||||
}
|
||||
if env.ResourceManagerEndpoint != testSubject.ResourceManagerEndpoint {
|
||||
t.Errorf("Expected ResourceManagerEndpoint to be %q, but got %q", env.ResourceManagerEndpoint, testSubject.ResourceManagerEndpoint)
|
||||
}
|
||||
if env.ActiveDirectoryEndpoint != testSubject.ActiveDirectoryEndpoint {
|
||||
t.Errorf("Expected ActiveDirectoryEndpoint to be %q, but got %q", env.ActiveDirectoryEndpoint, testSubject.ActiveDirectoryEndpoint)
|
||||
}
|
||||
if env.GalleryEndpoint != testSubject.GalleryEndpoint {
|
||||
t.Errorf("Expected GalleryEndpoint to be %q, but got %q", env.GalleryEndpoint, testSubject.GalleryEndpoint)
|
||||
}
|
||||
if env.ServiceBusEndpoint != testSubject.ServiceBusEndpoint {
|
||||
t.Errorf("Expected ServiceBusEnpoint to be %q, but got %q", env.ServiceBusEndpoint, testSubject.ServiceBusEndpoint)
|
||||
}
|
||||
if env.KeyVaultEndpoint != testSubject.KeyVaultEndpoint {
|
||||
t.Errorf("Expected KeyVaultEndpoint to be %q, but got %q", env.KeyVaultEndpoint, testSubject.KeyVaultEndpoint)
|
||||
}
|
||||
if env.GraphEndpoint != testSubject.GraphEndpoint {
|
||||
t.Errorf("Expected GraphEndpoint to be %q, but got %q", env.GraphEndpoint, testSubject.GraphEndpoint)
|
||||
}
|
||||
if env.StorageEndpointSuffix != testSubject.StorageEndpointSuffix {
|
||||
t.Errorf("Expected StorageEndpointSuffix to be %q, but got %q", env.StorageEndpointSuffix, testSubject.StorageEndpointSuffix)
|
||||
}
|
||||
if env.SQLDatabaseDNSSuffix != testSubject.SQLDatabaseDNSSuffix {
|
||||
t.Errorf("Expected SQLDatabaseDNSSuffix to be %q, but got %q", env.SQLDatabaseDNSSuffix, testSubject.SQLDatabaseDNSSuffix)
|
||||
}
|
||||
if env.TrafficManagerDNSSuffix != testSubject.TrafficManagerDNSSuffix {
|
||||
t.Errorf("Expected TrafficManagerDNSSuffix to be %q, but got %q", env.TrafficManagerDNSSuffix, testSubject.TrafficManagerDNSSuffix)
|
||||
}
|
||||
if env.KeyVaultDNSSuffix != testSubject.KeyVaultDNSSuffix {
|
||||
t.Errorf("Expected KeyVaultDNSSuffix to be %q, but got %q", env.KeyVaultDNSSuffix, testSubject.KeyVaultDNSSuffix)
|
||||
}
|
||||
if env.ServiceBusEndpointSuffix != testSubject.ServiceBusEndpointSuffix {
|
||||
t.Errorf("Expected ServiceBusEndpointSuffix to be %q, but got %q", env.ServiceBusEndpointSuffix, testSubject.ServiceBusEndpointSuffix)
|
||||
}
|
||||
if env.ServiceManagementVMDNSSuffix != testSubject.ServiceManagementVMDNSSuffix {
|
||||
t.Errorf("Expected ServiceManagementVMDNSSuffix to be %q, but got %q", env.ServiceManagementVMDNSSuffix, testSubject.ServiceManagementVMDNSSuffix)
|
||||
}
|
||||
if env.ResourceManagerVMDNSSuffix != testSubject.ResourceManagerVMDNSSuffix {
|
||||
t.Errorf("Expected ResourceManagerVMDNSSuffix to be %q, but got %q", env.ResourceManagerVMDNSSuffix, testSubject.ResourceManagerVMDNSSuffix)
|
||||
}
|
||||
if env.ContainerRegistryDNSSuffix != testSubject.ContainerRegistryDNSSuffix {
|
||||
t.Errorf("Expected ContainerRegistryDNSSuffix to be %q, but got %q", env.ContainerRegistryDNSSuffix, testSubject.ContainerRegistryDNSSuffix)
|
||||
}
|
||||
}
|
||||
169
vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go
generated
vendored
169
vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go
generated
vendored
|
|
@ -1,169 +0,0 @@
|
|||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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 azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
func TestDoRetryWithRegistration(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
// first response, should retry because it is a transient error
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError))
|
||||
// response indicates the resource provider has not been registered
|
||||
client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{
|
||||
"error":{
|
||||
"code":"MissingSubscriptionRegistration",
|
||||
"message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions.",
|
||||
"details":[
|
||||
{
|
||||
"code":"MissingSubscriptionRegistration",
|
||||
"target":"Microsoft.EventGrid",
|
||||
"message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`), http.StatusConflict, "MissingSubscriptionRegistration"))
|
||||
// first poll response, still not ready
|
||||
client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{
|
||||
"registrationState": "Registering"
|
||||
}
|
||||
`), http.StatusOK, "200 OK"))
|
||||
// last poll response, respurce provider has been registered
|
||||
client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{
|
||||
"registrationState": "Registered"
|
||||
}
|
||||
`), http.StatusOK, "200 OK"))
|
||||
// retry original request, response is successful
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
|
||||
|
||||
req := mocks.NewRequestForURL("https://lol/subscriptions/rofl")
|
||||
req.Body = mocks.NewBody("lolol")
|
||||
r, err := autorest.SendWithSender(client, req,
|
||||
DoRetryWithRegistration(autorest.Client{
|
||||
PollingDelay: time.Second,
|
||||
PollingDuration: time.Second * 10,
|
||||
RetryAttempts: 5,
|
||||
RetryDuration: time.Second,
|
||||
Sender: client,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("got error: %v", err)
|
||||
}
|
||||
|
||||
autorest.Respond(r,
|
||||
autorest.ByDiscardingBody(),
|
||||
autorest.ByClosing(),
|
||||
)
|
||||
|
||||
if r.StatusCode != http.StatusOK {
|
||||
t.Fatalf("azure: Sender#DoRetryWithRegistration -- Got: StatusCode %v; Want: StatusCode 200 OK", r.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetrySkipRegistration(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
// first response, should retry because it is a transient error
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError))
|
||||
// response indicates the resource provider has not been registered
|
||||
client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{
|
||||
"error":{
|
||||
"code":"MissingSubscriptionRegistration",
|
||||
"message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions.",
|
||||
"details":[
|
||||
{
|
||||
"code":"MissingSubscriptionRegistration",
|
||||
"target":"Microsoft.EventGrid",
|
||||
"message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions."
|
||||
}
|
||||
]
|
||||
}
|
||||
}`), http.StatusConflict, "MissingSubscriptionRegistration"))
|
||||
|
||||
req := mocks.NewRequestForURL("https://lol/subscriptions/rofl")
|
||||
req.Body = mocks.NewBody("lolol")
|
||||
r, err := autorest.SendWithSender(client, req,
|
||||
DoRetryWithRegistration(autorest.Client{
|
||||
PollingDelay: time.Second,
|
||||
PollingDuration: time.Second * 10,
|
||||
RetryAttempts: 5,
|
||||
RetryDuration: time.Second,
|
||||
Sender: client,
|
||||
SkipResourceProviderRegistration: true,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("got error: %v", err)
|
||||
}
|
||||
|
||||
autorest.Respond(r,
|
||||
autorest.ByDiscardingBody(),
|
||||
autorest.ByClosing(),
|
||||
)
|
||||
|
||||
if r.StatusCode != http.StatusConflict {
|
||||
t.Fatalf("azure: Sender#DoRetryWithRegistration -- Got: StatusCode %v; Want: StatusCode 409 Conflict", r.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryWithRegistration_CanBeCancelled(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
delay := 5 * time.Second
|
||||
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError), 5)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
start := time.Now()
|
||||
end := time.Now()
|
||||
var err error
|
||||
|
||||
go func() {
|
||||
req := mocks.NewRequestForURL("https://lol/subscriptions/rofl")
|
||||
req = req.WithContext(ctx)
|
||||
req.Body = mocks.NewBody("lolol")
|
||||
_, err = autorest.SendWithSender(client, req,
|
||||
DoRetryWithRegistration(autorest.Client{
|
||||
PollingDelay: time.Second,
|
||||
PollingDuration: delay,
|
||||
RetryAttempts: 5,
|
||||
RetryDuration: time.Second,
|
||||
Sender: client,
|
||||
SkipResourceProviderRegistration: true,
|
||||
}),
|
||||
)
|
||||
end = time.Now()
|
||||
wg.Done()
|
||||
}()
|
||||
cancel()
|
||||
wg.Wait()
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
if err == nil {
|
||||
t.Fatalf("azure: DoRetryWithRegistration didn't cancel")
|
||||
}
|
||||
if end.Sub(start) >= delay {
|
||||
t.Fatalf("azure: DoRetryWithRegistration failed to cancel")
|
||||
}
|
||||
}
|
||||
415
vendor/github.com/Azure/go-autorest/autorest/client_test.go
generated
vendored
415
vendor/github.com/Azure/go-autorest/autorest/client_test.go
generated
vendored
|
|
@ -1,415 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
"github.com/Azure/go-autorest/tracing"
|
||||
)
|
||||
|
||||
func TestLoggingInspectorWithInspection(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.RequestInspector = li.WithInspection()
|
||||
|
||||
Prepare(mocks.NewRequestWithContent("Content"),
|
||||
c.WithInspection())
|
||||
|
||||
if len(b.String()) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggingInspectorWithInspectionEmitsErrors(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
r := mocks.NewRequestWithContent("Content")
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.RequestInspector = li.WithInspection()
|
||||
|
||||
if _, err := Prepare(r,
|
||||
c.WithInspection()); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(b.String()) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggingInspectorWithInspectionRestoresBody(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
r := mocks.NewRequestWithContent("Content")
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.RequestInspector = li.WithInspection()
|
||||
|
||||
Prepare(r,
|
||||
c.WithInspection())
|
||||
|
||||
s, _ := ioutil.ReadAll(r.Body)
|
||||
if len(s) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#WithInspection did not restore the Request body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggingInspectorByInspecting(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.ResponseInspector = li.ByInspecting()
|
||||
|
||||
Respond(mocks.NewResponseWithContent("Content"),
|
||||
c.ByInspecting())
|
||||
|
||||
if len(b.String()) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggingInspectorByInspectingEmitsErrors(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
r := mocks.NewResponseWithContent("Content")
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.ResponseInspector = li.ByInspecting()
|
||||
|
||||
if err := Respond(r,
|
||||
c.ByInspecting()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(b.String()) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggingInspectorByInspectingRestoresBody(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
c := Client{}
|
||||
r := mocks.NewResponseWithContent("Content")
|
||||
li := LoggingInspector{Logger: log.New(&b, "", 0)}
|
||||
c.ResponseInspector = li.ByInspecting()
|
||||
|
||||
Respond(r,
|
||||
c.ByInspecting())
|
||||
|
||||
s, _ := ioutil.ReadAll(r.Body)
|
||||
if len(s) <= 0 {
|
||||
t.Fatal("autorest: LoggingInspector#ByInspecting did not restore the Response body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientWithUserAgent(t *testing.T) {
|
||||
ua := "UserAgent"
|
||||
c := NewClientWithUserAgent(ua)
|
||||
completeUA := fmt.Sprintf("%s %s", UserAgent(), ua)
|
||||
|
||||
if c.UserAgent != completeUA {
|
||||
t.Fatalf("autorest: NewClientWithUserAgent failed to set the UserAgent -- expected %s, received %s",
|
||||
completeUA, c.UserAgent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddToUserAgent(t *testing.T) {
|
||||
ua := "UserAgent"
|
||||
c := NewClientWithUserAgent(ua)
|
||||
ext := "extension"
|
||||
err := c.AddToUserAgent(ext)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: AddToUserAgent returned error -- expected nil, received %s", err)
|
||||
}
|
||||
completeUA := fmt.Sprintf("%s %s %s", UserAgent(), ua, ext)
|
||||
|
||||
if c.UserAgent != completeUA {
|
||||
t.Fatalf("autorest: AddToUserAgent failed to add an extension to the UserAgent -- expected %s, received %s",
|
||||
completeUA, c.UserAgent)
|
||||
}
|
||||
|
||||
err = c.AddToUserAgent("")
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: AddToUserAgent didn't return error -- expected %s, received nil",
|
||||
fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent))
|
||||
}
|
||||
if c.UserAgent != completeUA {
|
||||
t.Fatalf("autorest: AddToUserAgent failed to not add an empty extension to the UserAgent -- expected %s, received %s",
|
||||
completeUA, c.UserAgent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSenderReturnsHttpClientByDefault(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
if fmt.Sprintf("%T", c.sender()) != "*http.Client" {
|
||||
t.Fatal("autorest: Client#sender failed to return http.Client by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSenderReturnsSetSender(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
s := mocks.NewSender()
|
||||
c.Sender = s
|
||||
|
||||
if c.sender() != s {
|
||||
t.Fatal("autorest: Client#sender failed to return set Sender")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoInvokesSender(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
s := mocks.NewSender()
|
||||
c.Sender = s
|
||||
|
||||
c.Do(&http.Request{})
|
||||
if s.Attempts() != 1 {
|
||||
t.Fatal("autorest: Client#Do failed to invoke the Sender")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoSetsUserAgent(t *testing.T) {
|
||||
ua := "UserAgent"
|
||||
c := Client{UserAgent: ua}
|
||||
r := mocks.NewRequest()
|
||||
s := mocks.NewSender()
|
||||
c.Sender = s
|
||||
|
||||
c.Do(r)
|
||||
|
||||
if r.UserAgent() != ua {
|
||||
t.Fatalf("autorest: Client#Do failed to correctly set User-Agent header: %s=%s",
|
||||
http.CanonicalHeaderKey(headerUserAgent), r.UserAgent())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoSetsAuthorization(t *testing.T) {
|
||||
r := mocks.NewRequest()
|
||||
s := mocks.NewSender()
|
||||
c := Client{Authorizer: mockAuthorizer{}, Sender: s}
|
||||
|
||||
c.Do(r)
|
||||
if len(r.Header.Get(http.CanonicalHeaderKey(headerAuthorization))) <= 0 {
|
||||
t.Fatalf("autorest: Client#Send failed to set Authorization header -- %s=%s",
|
||||
http.CanonicalHeaderKey(headerAuthorization),
|
||||
r.Header.Get(http.CanonicalHeaderKey(headerAuthorization)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoInvokesRequestInspector(t *testing.T) {
|
||||
r := mocks.NewRequest()
|
||||
s := mocks.NewSender()
|
||||
i := &mockInspector{}
|
||||
c := Client{RequestInspector: i.WithInspection(), Sender: s}
|
||||
|
||||
c.Do(r)
|
||||
if !i.wasInvoked {
|
||||
t.Fatal("autorest: Client#Send failed to invoke the RequestInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoInvokesResponseInspector(t *testing.T) {
|
||||
r := mocks.NewRequest()
|
||||
s := mocks.NewSender()
|
||||
i := &mockInspector{}
|
||||
c := Client{ResponseInspector: i.ByInspecting(), Sender: s}
|
||||
|
||||
c.Do(r)
|
||||
if !i.wasInvoked {
|
||||
t.Fatal("autorest: Client#Send failed to invoke the ResponseInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoReturnsErrorIfPrepareFails(t *testing.T) {
|
||||
c := Client{}
|
||||
s := mocks.NewSender()
|
||||
c.Authorizer = mockFailingAuthorizer{}
|
||||
c.Sender = s
|
||||
|
||||
_, err := c.Do(&http.Request{})
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: Client#Do failed to return an error when Prepare failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoDoesNotSendIfPrepareFails(t *testing.T) {
|
||||
c := Client{}
|
||||
s := mocks.NewSender()
|
||||
c.Authorizer = mockFailingAuthorizer{}
|
||||
c.Sender = s
|
||||
|
||||
c.Do(&http.Request{})
|
||||
if s.Attempts() > 0 {
|
||||
t.Fatal("autorest: Client#Do failed to invoke the Sender")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientAuthorizerReturnsNullAuthorizerByDefault(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
if fmt.Sprintf("%T", c.authorizer()) != "autorest.NullAuthorizer" {
|
||||
t.Fatal("autorest: Client#authorizer failed to return the NullAuthorizer by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientAuthorizerReturnsSetAuthorizer(t *testing.T) {
|
||||
c := Client{}
|
||||
c.Authorizer = mockAuthorizer{}
|
||||
|
||||
if fmt.Sprintf("%T", c.authorizer()) != "autorest.mockAuthorizer" {
|
||||
t.Fatal("autorest: Client#authorizer failed to return the set Authorizer")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientWithAuthorizer(t *testing.T) {
|
||||
c := Client{}
|
||||
c.Authorizer = mockAuthorizer{}
|
||||
|
||||
req, _ := Prepare(&http.Request{},
|
||||
c.WithAuthorization())
|
||||
|
||||
if req.Header.Get(headerAuthorization) == "" {
|
||||
t.Fatal("autorest: Client#WithAuthorizer failed to return the WithAuthorizer from the active Authorizer")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientWithInspection(t *testing.T) {
|
||||
c := Client{}
|
||||
r := &mockInspector{}
|
||||
c.RequestInspector = r.WithInspection()
|
||||
|
||||
Prepare(&http.Request{},
|
||||
c.WithInspection())
|
||||
|
||||
if !r.wasInvoked {
|
||||
t.Fatal("autorest: Client#WithInspection failed to invoke RequestInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientWithInspectionSetsDefault(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
r1 := &http.Request{}
|
||||
r2, _ := Prepare(r1,
|
||||
c.WithInspection())
|
||||
|
||||
if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatal("autorest: Client#WithInspection failed to provide a default RequestInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientByInspecting(t *testing.T) {
|
||||
c := Client{}
|
||||
r := &mockInspector{}
|
||||
c.ResponseInspector = r.ByInspecting()
|
||||
|
||||
Respond(&http.Response{},
|
||||
c.ByInspecting())
|
||||
|
||||
if !r.wasInvoked {
|
||||
t.Fatal("autorest: Client#ByInspecting failed to invoke ResponseInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientByInspectingSetsDefault(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
r := &http.Response{}
|
||||
Respond(r,
|
||||
c.ByInspecting())
|
||||
|
||||
if !reflect.DeepEqual(r, &http.Response{}) {
|
||||
t.Fatal("autorest: Client#ByInspecting failed to provide a default ResponseInspector")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientTracing(t *testing.T) {
|
||||
c := Client{}
|
||||
|
||||
httpClient, ok := c.sender().(*http.Client)
|
||||
if !ok {
|
||||
t.Fatal("autorest: Client#sender failed to return http.Client by default")
|
||||
}
|
||||
if httpClient.Transport != tracing.Transport {
|
||||
t.Fatal("autorest: Client.Sender Default transport is not the tracing transport")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCookies(t *testing.T) {
|
||||
second := "second"
|
||||
expected := http.Cookie{
|
||||
Name: "tastes",
|
||||
Value: "delicious",
|
||||
}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.SetCookie(w, &expected)
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ioutil.ReadAll failed reading request body: %s", err)
|
||||
}
|
||||
if string(b) == second {
|
||||
cookie, err := r.Cookie(expected.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: r.Cookie could not get request cookie: %s", err)
|
||||
}
|
||||
if cookie == nil {
|
||||
t.Fatalf("autorest: got nil cookie, expecting %v", expected)
|
||||
}
|
||||
if cookie.Value != expected.Value {
|
||||
t.Fatalf("autorest: got cookie value '%s', expecting '%s'", cookie.Value, expected.Name)
|
||||
}
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClientWithUserAgent("")
|
||||
_, err := SendWithSender(client, mocks.NewRequestForURL(server.URL))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: first request failed: %s", err)
|
||||
}
|
||||
|
||||
r2, err := http.NewRequest(http.MethodGet, server.URL, mocks.NewBody(second))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: failed creating second request: %s", err)
|
||||
}
|
||||
|
||||
_, err = SendWithSender(client, r2)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: second request failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func randomString(n int) string {
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
|
||||
s := make([]byte, n)
|
||||
for i := range s {
|
||||
s[i] = chars[r.Intn(len(chars))]
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
237
vendor/github.com/Azure/go-autorest/autorest/date/date_test.go
generated
vendored
237
vendor/github.com/Azure/go-autorest/autorest/date/date_test.go
generated
vendored
|
|
@ -1,237 +0,0 @@
|
|||
package date
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleParseDate() {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func ExampleDate() {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "2001-02-04T00:00:00Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Date acts as time.Time when the receiver
|
||||
if d.Before(t) {
|
||||
fmt.Printf("Before ")
|
||||
} else {
|
||||
fmt.Printf("After ")
|
||||
}
|
||||
|
||||
// Convert Date when needing a time.Time
|
||||
if t.After(d.ToTime()) {
|
||||
fmt.Printf("After")
|
||||
} else {
|
||||
fmt.Printf("Before")
|
||||
}
|
||||
// Output: Before After
|
||||
}
|
||||
|
||||
func ExampleDate_MarshalBinary() {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
t, err := d.MarshalBinary()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(t))
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func ExampleDate_UnmarshalBinary() {
|
||||
d := Date{}
|
||||
t := "2001-02-03"
|
||||
|
||||
if err := d.UnmarshalBinary([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func ExampleDate_MarshalJSON() {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
j, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(j))
|
||||
// Output: "2001-02-03"
|
||||
}
|
||||
|
||||
func ExampleDate_UnmarshalJSON() {
|
||||
var d struct {
|
||||
Date Date `json:"date"`
|
||||
}
|
||||
j := `{"date" : "2001-02-03"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d.Date)
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func ExampleDate_MarshalText() {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
t, err := d.MarshalText()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(t))
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func ExampleDate_UnmarshalText() {
|
||||
d := Date{}
|
||||
t := "2001-02-03"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03
|
||||
}
|
||||
|
||||
func TestDateString(t *testing.T) {
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
t.Fatalf("date: String failed (%v)", err)
|
||||
}
|
||||
if d.String() != "2001-02-03" {
|
||||
t.Fatalf("date: String failed (%v)", d.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateBinaryRoundTrip(t *testing.T) {
|
||||
d1, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
t.Fatalf("date: ParseDate failed (%v)", err)
|
||||
}
|
||||
t1, err := d1.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("date: MarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := Date{}
|
||||
if err = d2.UnmarshalBinary(t1); err != nil {
|
||||
t.Fatalf("date: UnmarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip Binary failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateJSONRoundTrip(t *testing.T) {
|
||||
type s struct {
|
||||
Date Date `json:"date"`
|
||||
}
|
||||
var err error
|
||||
d1 := s{}
|
||||
d1.Date, err = ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
t.Fatalf("date: ParseDate failed (%v)", err)
|
||||
}
|
||||
|
||||
j, err := json.Marshal(d1)
|
||||
if err != nil {
|
||||
t.Fatalf("date: MarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := s{}
|
||||
if err = json.Unmarshal(j, &d2); err != nil {
|
||||
t.Fatalf("date: UnmarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTextRoundTrip(t *testing.T) {
|
||||
d1, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
t.Fatalf("date: ParseDate failed (%v)", err)
|
||||
}
|
||||
t1, err := d1.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatalf("date: MarshalText failed (%v)", err)
|
||||
}
|
||||
d2 := Date{}
|
||||
if err = d2.UnmarshalText(t1); err != nil {
|
||||
t.Fatalf("date: UnmarshalText failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateToTime(t *testing.T) {
|
||||
var d Date
|
||||
d, err := ParseDate("2001-02-03")
|
||||
if err != nil {
|
||||
t.Fatalf("date: ParseDate failed (%v)", err)
|
||||
}
|
||||
var _ time.Time = d.ToTime()
|
||||
}
|
||||
|
||||
func TestDateUnmarshalJSONReturnsError(t *testing.T) {
|
||||
var d struct {
|
||||
Date Date `json:"date"`
|
||||
}
|
||||
j := `{"date" : "February 3, 2001"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err == nil {
|
||||
t.Fatal("date: Date failed to return error for malformed JSON date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateUnmarshalTextReturnsError(t *testing.T) {
|
||||
d := Date{}
|
||||
txt := "February 3, 2001"
|
||||
|
||||
if err := d.UnmarshalText([]byte(txt)); err == nil {
|
||||
t.Fatal("date: Date failed to return error for malformed Text date")
|
||||
}
|
||||
}
|
||||
277
vendor/github.com/Azure/go-autorest/autorest/date/time_test.go
generated
vendored
277
vendor/github.com/Azure/go-autorest/autorest/date/time_test.go
generated
vendored
|
|
@ -1,277 +0,0 @@
|
|||
package date
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleParseTime() {
|
||||
d, _ := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03 04:05:06 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleTime_MarshalBinary() {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := Time{ti}
|
||||
t, err := d.MarshalBinary()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(t))
|
||||
// Output: 2001-02-03T04:05:06Z
|
||||
}
|
||||
|
||||
func ExampleTime_UnmarshalBinary() {
|
||||
d := Time{}
|
||||
t := "2001-02-03T04:05:06Z"
|
||||
|
||||
if err := d.UnmarshalBinary([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03T04:05:06Z
|
||||
}
|
||||
|
||||
func ExampleTime_MarshalJSON() {
|
||||
d, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
j, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(j))
|
||||
// Output: "2001-02-03T04:05:06Z"
|
||||
}
|
||||
|
||||
func ExampleTime_UnmarshalJSON() {
|
||||
var d struct {
|
||||
Time Time `json:"datetime"`
|
||||
}
|
||||
j := `{"datetime" : "2001-02-03T04:05:06Z"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d.Time)
|
||||
// Output: 2001-02-03T04:05:06Z
|
||||
}
|
||||
|
||||
func ExampleTime_MarshalText() {
|
||||
d, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
t, err := d.MarshalText()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(t))
|
||||
// Output: 2001-02-03T04:05:06Z
|
||||
}
|
||||
|
||||
func ExampleTime_UnmarshalText() {
|
||||
d := Time{}
|
||||
t := "2001-02-03T04:05:06Z"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2001-02-03T04:05:06Z
|
||||
}
|
||||
|
||||
func TestUnmarshalTextforInvalidDate(t *testing.T) {
|
||||
d := Time{}
|
||||
dt := "2001-02-03T04:05:06AAA"
|
||||
|
||||
if err := d.UnmarshalText([]byte(dt)); err == nil {
|
||||
t.Fatalf("date: Time#Unmarshal was expecting error for invalid date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJSONforInvalidDate(t *testing.T) {
|
||||
d := Time{}
|
||||
dt := `"2001-02-03T04:05:06AAA"`
|
||||
|
||||
if err := d.UnmarshalJSON([]byte(dt)); err == nil {
|
||||
t.Fatalf("date: Time#Unmarshal was expecting error for invalid date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeString(t *testing.T) {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := Time{ti}
|
||||
if d.String() != "2001-02-03T04:05:06Z" {
|
||||
t.Fatalf("date: Time#String failed (%v)", d.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeStringReturnsEmptyStringForError(t *testing.T) {
|
||||
d := Time{Time: time.Date(20000, 01, 01, 01, 01, 01, 01, time.UTC)}
|
||||
if d.String() != "" {
|
||||
t.Fatalf("date: Time#String failed empty string for an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeBinaryRoundTrip(t *testing.T) {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#ParseTime failed (%v)", err)
|
||||
}
|
||||
d1 := Time{ti}
|
||||
t1, err := d1.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#MarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := Time{}
|
||||
if err = d2.UnmarshalBinary(t1); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date:Round-trip Binary failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeJSONRoundTrip(t *testing.T) {
|
||||
type s struct {
|
||||
Time Time `json:"datetime"`
|
||||
}
|
||||
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#ParseTime failed (%v)", err)
|
||||
}
|
||||
|
||||
d1 := s{Time: Time{ti}}
|
||||
j, err := json.Marshal(d1)
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#MarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := s{}
|
||||
if err = json.Unmarshal(j, &d2); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeTextRoundTrip(t *testing.T) {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#ParseTime failed (%v)", err)
|
||||
}
|
||||
d1 := Time{Time: ti}
|
||||
t1, err := d1.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#MarshalText failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := Time{}
|
||||
if err = d2.UnmarshalText(t1); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalText failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeToTime(t *testing.T) {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
d := Time{ti}
|
||||
if err != nil {
|
||||
t.Fatalf("date: Time#ParseTime failed (%v)", err)
|
||||
}
|
||||
var _ time.Time = d.ToTime()
|
||||
}
|
||||
|
||||
func TestUnmarshalJSONNoOffset(t *testing.T) {
|
||||
var d struct {
|
||||
Time Time `json:"datetime"`
|
||||
}
|
||||
j := `{"datetime" : "2001-02-03T04:05:06.789"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
t.Fatalf("date: Time#Unmarshal failed (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJSONPosOffset(t *testing.T) {
|
||||
var d struct {
|
||||
Time Time `json:"datetime"`
|
||||
}
|
||||
j := `{"datetime" : "1980-01-02T00:11:35.01+01:00"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
t.Fatalf("date: Time#Unmarshal failed (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJSONNegOffset(t *testing.T) {
|
||||
var d struct {
|
||||
Time Time `json:"datetime"`
|
||||
}
|
||||
j := `{"datetime" : "1492-10-12T10:15:01.789-08:00"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
t.Fatalf("date: Time#Unmarshal failed (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalTextNoOffset(t *testing.T) {
|
||||
d := Time{}
|
||||
t1 := "2001-02-03T04:05:06"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t1)); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalText failed (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalTextPosOffset(t *testing.T) {
|
||||
d := Time{}
|
||||
t1 := "2001-02-03T04:05:06+00:30"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t1)); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalText failed (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalTextNegOffset(t *testing.T) {
|
||||
d := Time{}
|
||||
t1 := "2001-02-03T04:05:06-11:00"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t1)); err != nil {
|
||||
t.Fatalf("date: Time#UnmarshalText failed (%v)", err)
|
||||
}
|
||||
}
|
||||
226
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go
generated
vendored
226
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go
generated
vendored
|
|
@ -1,226 +0,0 @@
|
|||
package date
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleTimeRFC1123() {
|
||||
d, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: 2006-01-02 15:04:05 +0000 MST
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_MarshalBinary() {
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := TimeRFC1123{ti}
|
||||
b, err := d.MarshalBinary()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
// Output: Mon, 02 Jan 2006 15:04:05 MST
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_UnmarshalBinary() {
|
||||
d := TimeRFC1123{}
|
||||
t := "Mon, 02 Jan 2006 15:04:05 MST"
|
||||
if err := d.UnmarshalBinary([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: Mon, 02 Jan 2006 15:04:05 MST
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_MarshalJSON() {
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := TimeRFC1123{ti}
|
||||
j, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(j))
|
||||
// Output: "Mon, 02 Jan 2006 15:04:05 MST"
|
||||
}
|
||||
|
||||
func TestTimeRFC1123MarshalJSONInvalid(t *testing.T) {
|
||||
ti := time.Date(20000, 01, 01, 00, 00, 00, 00, time.UTC)
|
||||
d := TimeRFC1123{ti}
|
||||
if _, err := json.Marshal(d); err == nil {
|
||||
t.Fatalf("date: TimeRFC1123#Marshal failed for invalid date")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_UnmarshalJSON() {
|
||||
var d struct {
|
||||
Time TimeRFC1123 `json:"datetime"`
|
||||
}
|
||||
j := `{"datetime" : "Mon, 02 Jan 2006 15:04:05 MST"}`
|
||||
|
||||
if err := json.Unmarshal([]byte(j), &d); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d.Time)
|
||||
// Output: Mon, 02 Jan 2006 15:04:05 MST
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_MarshalText() {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := TimeRFC1123{ti}
|
||||
t, err := d.MarshalText()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(string(t))
|
||||
// Output: Sat, 03 Feb 2001 04:05:06 UTC
|
||||
}
|
||||
|
||||
func ExampleTimeRFC1123_UnmarshalText() {
|
||||
d := TimeRFC1123{}
|
||||
t := "Sat, 03 Feb 2001 04:05:06 UTC"
|
||||
|
||||
if err := d.UnmarshalText([]byte(t)); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(d)
|
||||
// Output: Sat, 03 Feb 2001 04:05:06 UTC
|
||||
}
|
||||
|
||||
func TestUnmarshalJSONforInvalidDateRfc1123(t *testing.T) {
|
||||
dt := `"Mon, 02 Jan 2000000 15:05 MST"`
|
||||
d := TimeRFC1123{}
|
||||
if err := d.UnmarshalJSON([]byte(dt)); err == nil {
|
||||
t.Fatalf("date: TimeRFC1123#Unmarshal failed for invalid date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalTextforInvalidDateRfc1123(t *testing.T) {
|
||||
dt := "Mon, 02 Jan 2000000 15:05 MST"
|
||||
d := TimeRFC1123{}
|
||||
if err := d.UnmarshalText([]byte(dt)); err == nil {
|
||||
t.Fatalf("date: TimeRFC1123#Unmarshal failed for invalid date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeStringRfc1123(t *testing.T) {
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
d := TimeRFC1123{ti}
|
||||
if d.String() != "Mon, 02 Jan 2006 15:04:05 MST" {
|
||||
t.Fatalf("date: TimeRFC1123#String failed (%v)", d.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeStringReturnsEmptyStringForErrorRfc1123(t *testing.T) {
|
||||
d := TimeRFC1123{Time: time.Date(20000, 01, 01, 01, 01, 01, 01, time.UTC)}
|
||||
if d.String() != "" {
|
||||
t.Fatalf("date: TimeRFC1123#String failed empty string for an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeBinaryRoundTripRfc1123(t *testing.T) {
|
||||
ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z")
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err)
|
||||
}
|
||||
d1 := TimeRFC1123{ti}
|
||||
t1, err := d1.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#MarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := TimeRFC1123{}
|
||||
if err = d2.UnmarshalBinary(t1); err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#UnmarshalBinary failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip Binary failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeJSONRoundTripRfc1123(t *testing.T) {
|
||||
type s struct {
|
||||
Time TimeRFC1123 `json:"datetime"`
|
||||
}
|
||||
var err error
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err)
|
||||
}
|
||||
d1 := s{Time: TimeRFC1123{ti}}
|
||||
j, err := json.Marshal(d1)
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#MarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := s{}
|
||||
if err = json.Unmarshal(j, &d2); err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#UnmarshalJSON failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeTextRoundTripRfc1123(t *testing.T) {
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err)
|
||||
}
|
||||
d1 := TimeRFC1123{Time: ti}
|
||||
t1, err := d1.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#MarshalText failed (%v)", err)
|
||||
}
|
||||
|
||||
d2 := TimeRFC1123{}
|
||||
if err = d2.UnmarshalText(t1); err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#UnmarshalText failed (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(d1, d2) {
|
||||
t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeToTimeRFC1123(t *testing.T) {
|
||||
ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
d := TimeRFC1123{ti}
|
||||
if err != nil {
|
||||
t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err)
|
||||
}
|
||||
var _ time.Time = d.ToTime()
|
||||
}
|
||||
283
vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go
generated
vendored
283
vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go
generated
vendored
|
|
@ -1,283 +0,0 @@
|
|||
// +build go1.7
|
||||
|
||||
package date
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleUnixTime_MarshalJSON() {
|
||||
epoch := UnixTime(UnixEpoch())
|
||||
text, _ := json.Marshal(epoch)
|
||||
fmt.Print(string(text))
|
||||
// Output: 0
|
||||
}
|
||||
|
||||
func ExampleUnixTime_UnmarshalJSON() {
|
||||
var myTime UnixTime
|
||||
json.Unmarshal([]byte("1.3e2"), &myTime)
|
||||
fmt.Printf("%v", time.Time(myTime))
|
||||
// Output: 1970-01-01 00:02:10 +0000 UTC
|
||||
}
|
||||
|
||||
func TestUnixTime_MarshalJSON(t *testing.T) {
|
||||
testCases := []time.Time{
|
||||
UnixEpoch().Add(-1 * time.Second), // One second befote the Unix Epoch
|
||||
time.Date(2017, time.April, 14, 20, 27, 47, 0, time.UTC), // The time this test was written
|
||||
UnixEpoch(),
|
||||
time.Date(1800, 01, 01, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2200, 12, 29, 00, 01, 37, 82, time.UTC),
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.String(), func(subT *testing.T) {
|
||||
var actual, expected float64
|
||||
var marshaled []byte
|
||||
|
||||
target := UnixTime(tc)
|
||||
expected = float64(target.Duration().Nanoseconds()) / 1e9
|
||||
|
||||
if temp, err := json.Marshal(target); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(bytes.NewReader(marshaled))
|
||||
if err := dec.Decode(&actual); err != nil {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
diff := math.Abs(actual - expected)
|
||||
subT.Logf("\ngot :\t%g\nwant:\t%g\ndiff:\t%g", actual, expected, diff)
|
||||
if diff > 1e-9 { //Must be within 1 nanosecond of one another
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_UnmarshalJSON(t *testing.T) {
|
||||
testCases := []struct {
|
||||
text string
|
||||
expected time.Time
|
||||
}{
|
||||
{"1", UnixEpoch().Add(time.Second)},
|
||||
{"0", UnixEpoch()},
|
||||
{"1492203742", time.Date(2017, time.April, 14, 21, 02, 22, 0, time.UTC)}, // The time this test was written
|
||||
{"-1", time.Date(1969, time.December, 31, 23, 59, 59, 0, time.UTC)},
|
||||
{"1.5", UnixEpoch().Add(1500 * time.Millisecond)},
|
||||
{"0e1", UnixEpoch()}, // See http://json.org for 'number' format definition.
|
||||
{"1.3e+2", UnixEpoch().Add(130 * time.Second)},
|
||||
{"1.6E-10", UnixEpoch()}, // This is so small, it should get truncated into the UnixEpoch
|
||||
{"2E-6", UnixEpoch().Add(2 * time.Microsecond)},
|
||||
{"1.289345e9", UnixEpoch().Add(1289345000 * time.Second)},
|
||||
{"1e-9", UnixEpoch().Add(time.Nanosecond)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.text, func(subT *testing.T) {
|
||||
var rehydrated UnixTime
|
||||
if err := json.Unmarshal([]byte(tc.text), &rehydrated); err != nil {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if time.Time(rehydrated) != tc.expected {
|
||||
subT.Logf("\ngot: \t%v\nwant:\t%v\ndiff:\t%v", time.Time(rehydrated), tc.expected, time.Time(rehydrated).Sub(tc.expected))
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_JSONRoundTrip(t *testing.T) {
|
||||
testCases := []time.Time{
|
||||
UnixEpoch(),
|
||||
time.Date(2005, time.November, 5, 0, 0, 0, 0, time.UTC), // The day V for Vendetta (film) was released.
|
||||
UnixEpoch().Add(-6 * time.Second),
|
||||
UnixEpoch().Add(800 * time.Hour),
|
||||
UnixEpoch().Add(time.Nanosecond),
|
||||
time.Date(2015, time.September, 05, 4, 30, 12, 9992, time.UTC),
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.String(), func(subT *testing.T) {
|
||||
subject := UnixTime(tc)
|
||||
var marshaled []byte
|
||||
if temp, err := json.Marshal(subject); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var unmarshaled UnixTime
|
||||
if err := json.Unmarshal(marshaled, &unmarshaled); err != nil {
|
||||
subT.Error(err)
|
||||
}
|
||||
|
||||
actual := time.Time(unmarshaled)
|
||||
diff := actual.Sub(tc)
|
||||
subT.Logf("\ngot :\t%s\nwant:\t%s\ndiff:\t%s", actual.String(), tc.String(), diff.String())
|
||||
|
||||
if diff > time.Duration(100) { // We lose some precision be working in floats. We shouldn't lose more than 100 nanoseconds.
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_MarshalBinary(t *testing.T) {
|
||||
testCases := []struct {
|
||||
expected int64
|
||||
subject time.Time
|
||||
}{
|
||||
{0, UnixEpoch()},
|
||||
{-15 * int64(time.Second), UnixEpoch().Add(-15 * time.Second)},
|
||||
{54, UnixEpoch().Add(54 * time.Nanosecond)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run("", func(subT *testing.T) {
|
||||
var marshaled []byte
|
||||
|
||||
if temp, err := UnixTime(tc.subject).MarshalBinary(); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var unmarshaled int64
|
||||
if err := binary.Read(bytes.NewReader(marshaled), binary.LittleEndian, &unmarshaled); err != nil {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if unmarshaled != tc.expected {
|
||||
subT.Logf("\ngot: \t%d\nwant:\t%d", unmarshaled, tc.expected)
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_BinaryRoundTrip(t *testing.T) {
|
||||
testCases := []time.Time{
|
||||
UnixEpoch(),
|
||||
UnixEpoch().Add(800 * time.Minute),
|
||||
UnixEpoch().Add(7 * time.Hour),
|
||||
UnixEpoch().Add(-1 * time.Nanosecond),
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.String(), func(subT *testing.T) {
|
||||
original := UnixTime(tc)
|
||||
var marshaled []byte
|
||||
|
||||
if temp, err := original.MarshalBinary(); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var traveled UnixTime
|
||||
if err := traveled.UnmarshalBinary(marshaled); err != nil {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if traveled != original {
|
||||
subT.Logf("\ngot: \t%s\nwant:\t%s", time.Time(original).String(), time.Time(traveled).String())
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_MarshalText(t *testing.T) {
|
||||
testCases := []time.Time{
|
||||
UnixEpoch(),
|
||||
UnixEpoch().Add(45 * time.Second),
|
||||
UnixEpoch().Add(time.Nanosecond),
|
||||
UnixEpoch().Add(-100000 * time.Second),
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
expected, _ := tc.MarshalText()
|
||||
t.Run("", func(subT *testing.T) {
|
||||
var marshaled []byte
|
||||
|
||||
if temp, err := UnixTime(tc).MarshalText(); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if string(marshaled) != string(expected) {
|
||||
subT.Logf("\ngot: \t%s\nwant:\t%s", string(marshaled), string(expected))
|
||||
subT.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_TextRoundTrip(t *testing.T) {
|
||||
testCases := []time.Time{
|
||||
UnixEpoch(),
|
||||
UnixEpoch().Add(-1 * time.Nanosecond),
|
||||
UnixEpoch().Add(1 * time.Nanosecond),
|
||||
time.Date(2017, time.April, 17, 21, 00, 00, 00, time.UTC),
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.String(), func(subT *testing.T) {
|
||||
unixTC := UnixTime(tc)
|
||||
|
||||
var marshaled []byte
|
||||
|
||||
if temp, err := unixTC.MarshalText(); err == nil {
|
||||
marshaled = temp
|
||||
} else {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var unmarshaled UnixTime
|
||||
if err := unmarshaled.UnmarshalText(marshaled); err != nil {
|
||||
subT.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if unmarshaled != unixTC {
|
||||
t.Logf("\ngot: \t%s\nwant:\t%s", time.Time(unmarshaled).String(), tc.String())
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
202
vendor/github.com/Azure/go-autorest/autorest/error_test.go
generated
vendored
202
vendor/github.com/Azure/go-autorest/autorest/error_test.go
generated
vendored
|
|
@ -1,202 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewErrorWithError_AssignsPackageType(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if e.PackageType != "packageType" {
|
||||
t.Fatalf("autorest: Error failed to set package type -- expected %v, received %v", "packageType", e.PackageType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AssignsMethod(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if e.Method != "method" {
|
||||
t.Fatalf("autorest: Error failed to set method -- expected %v, received %v", "method", e.Method)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AssignsMessage(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if e.Message != "message" {
|
||||
t.Fatalf("autorest: Error failed to set message -- expected %v, received %v", "message", e.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AssignsUndefinedStatusCodeIfRespNil(t *testing.T) {
|
||||
e := NewErrorWithError(nil, "packageType", "method", nil, "message")
|
||||
if e.StatusCode != UndefinedStatusCode {
|
||||
t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", UndefinedStatusCode, e.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AssignsStatusCode(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", &http.Response{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Status: http.StatusText(http.StatusBadRequest)}, "message")
|
||||
|
||||
if e.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", http.StatusBadRequest, e.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AcceptsArgs(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message %s", "arg")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*arg.*`, e.Message); !matched {
|
||||
t.Fatalf("autorest: Error failed to apply message arguments -- expected %v, received %v",
|
||||
`.*arg.*`, e.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_AssignsError(t *testing.T) {
|
||||
err := fmt.Errorf("original")
|
||||
e := NewErrorWithError(err, "packageType", "method", nil, "message")
|
||||
|
||||
if e.Original != err {
|
||||
t.Fatalf("autorest: Error failed to set error -- expected %v, received %v", err, e.Original)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithResponse_ContainsStatusCode(t *testing.T) {
|
||||
e := NewErrorWithResponse("packageType", "method", &http.Response{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Status: http.StatusText(http.StatusBadRequest)}, "message")
|
||||
|
||||
if e.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", http.StatusBadRequest, e.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithResponse_nilResponse_ReportsUndefinedStatusCode(t *testing.T) {
|
||||
e := NewErrorWithResponse("packageType", "method", nil, "message")
|
||||
|
||||
if e.StatusCode != UndefinedStatusCode {
|
||||
t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", UndefinedStatusCode, e.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithResponse_Forwards(t *testing.T) {
|
||||
e1 := NewError("packageType", "method", "message %s", "arg")
|
||||
e2 := NewErrorWithResponse("packageType", "method", nil, "message %s", "arg")
|
||||
|
||||
if !reflect.DeepEqual(e1, e2) {
|
||||
t.Fatal("autorest: NewError did not return an error equivalent to NewErrorWithError")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_Forwards(t *testing.T) {
|
||||
e1 := NewError("packageType", "method", "message %s", "arg")
|
||||
e2 := NewErrorWithError(nil, "packageType", "method", nil, "message %s", "arg")
|
||||
|
||||
if !reflect.DeepEqual(e1, e2) {
|
||||
t.Fatal("autorest: NewError did not return an error equivalent to NewErrorWithError")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_DoesNotWrapADetailedError(t *testing.T) {
|
||||
e1 := NewError("packageType1", "method1", "message1 %s", "arg1")
|
||||
e2 := NewErrorWithError(e1, "packageType2", "method2", nil, "message2 %s", "arg2")
|
||||
|
||||
if !reflect.DeepEqual(e1, e2) {
|
||||
t.Fatalf("autorest: NewErrorWithError incorrectly wrapped a DetailedError -- expected %v, received %v", e1, e2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithError_WrapsAnError(t *testing.T) {
|
||||
e1 := fmt.Errorf("Inner Error")
|
||||
var e2 interface{} = NewErrorWithError(e1, "packageType", "method", nil, "message")
|
||||
|
||||
if _, ok := e2.(DetailedError); !ok {
|
||||
t.Fatalf("autorest: NewErrorWithError failed to wrap a standard error -- received %T", e2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedError(t *testing.T) {
|
||||
err := fmt.Errorf("original")
|
||||
e := NewErrorWithError(err, "packageType", "method", nil, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*original.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#Error failed to return original error message -- expected %v, received %v",
|
||||
`.*original.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorConstainsPackageType(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*packageType.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#String failed to include PackageType -- expected %v, received %v",
|
||||
`.*packageType.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorConstainsMethod(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*method.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#String failed to include Method -- expected %v, received %v",
|
||||
`.*method.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorConstainsMessage(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*message.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#String failed to include Message -- expected %v, received %v",
|
||||
`.*message.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorConstainsStatusCode(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", &http.Response{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Status: http.StatusText(http.StatusBadRequest)}, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*400.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#String failed to include Status Code -- expected %v, received %v",
|
||||
`.*400.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorConstainsOriginal(t *testing.T) {
|
||||
e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*original.*`, e.Error()); !matched {
|
||||
t.Fatalf("autorest: Error#String failed to include Original error -- expected %v, received %v",
|
||||
`.*original.*`, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetailedErrorSkipsOriginal(t *testing.T) {
|
||||
e := NewError("packageType", "method", "message")
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*Original.*`, e.Error()); matched {
|
||||
t.Fatalf("autorest: Error#String included missing Original error -- unexpected %v, received %v",
|
||||
`.*Original.*`, e.Error())
|
||||
}
|
||||
}
|
||||
802
vendor/github.com/Azure/go-autorest/autorest/preparer_test.go
generated
vendored
802
vendor/github.com/Azure/go-autorest/autorest/preparer_test.go
generated
vendored
|
|
@ -1,802 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
// PrepareDecorators wrap and invoke a Preparer. Most often, the decorator invokes the passed
|
||||
// Preparer and decorates the response.
|
||||
func ExamplePrepareDecorator() {
|
||||
path := "a/b/c/"
|
||||
pd := func() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r, err := p.Prepare(r)
|
||||
if err == nil {
|
||||
if r.URL == nil {
|
||||
return r, fmt.Errorf("ERROR: URL is not set")
|
||||
}
|
||||
r.URL.Path += path
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
r, _ := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
pd())
|
||||
|
||||
fmt.Printf("Path is %s\n", r.URL)
|
||||
// Output: Path is https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
// PrepareDecorators may also modify and then invoke the Preparer.
|
||||
func ExamplePrepareDecorator_pre() {
|
||||
pd := func() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
r.Header.Add(http.CanonicalHeaderKey("ContentType"), "application/json")
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
r, _ := Prepare(&http.Request{Header: http.Header{}},
|
||||
pd())
|
||||
|
||||
fmt.Printf("ContentType is %s\n", r.Header.Get("ContentType"))
|
||||
// Output: ContentType is application/json
|
||||
}
|
||||
|
||||
// Create a sequence of three Preparers that build up the URL path.
|
||||
func ExampleCreatePreparer() {
|
||||
p := CreatePreparer(
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPath("a"),
|
||||
WithPath("b"),
|
||||
WithPath("c"))
|
||||
r, err := p.Prepare(&http.Request{})
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c
|
||||
}
|
||||
|
||||
// Create and apply separate Preparers
|
||||
func ExampleCreatePreparer_multiple() {
|
||||
params := map[string]interface{}{
|
||||
"param1": "a",
|
||||
"param2": "c",
|
||||
}
|
||||
|
||||
p1 := CreatePreparer(WithBaseURL("https://microsoft.com/"))
|
||||
p2 := CreatePreparer(WithPathParameters("/{param1}/b/{param2}/", params))
|
||||
|
||||
r, err := p1.Prepare(&http.Request{})
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
}
|
||||
|
||||
r, err = p2.Prepare(r)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
// Create and chain separate Preparers
|
||||
func ExampleCreatePreparer_chain() {
|
||||
params := map[string]interface{}{
|
||||
"param1": "a",
|
||||
"param2": "c",
|
||||
}
|
||||
|
||||
p := CreatePreparer(WithBaseURL("https://microsoft.com/"))
|
||||
p = DecoratePreparer(p, WithPathParameters("/{param1}/b/{param2}/", params))
|
||||
|
||||
r, err := p.Prepare(&http.Request{})
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
// Create and prepare an http.Request in one call
|
||||
func ExamplePrepare() {
|
||||
r, err := Prepare(&http.Request{},
|
||||
AsGet(),
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPath("a/b/c/"))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("%s %s", r.Method, r.URL)
|
||||
}
|
||||
// Output: GET https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
// Create a request for a supplied base URL and path
|
||||
func ExampleWithBaseURL() {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/a/b/c/"))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
func ExampleWithBaseURL_second() {
|
||||
_, err := Prepare(&http.Request{}, WithBaseURL(":"))
|
||||
fmt.Println(err)
|
||||
// Output: parse :: missing protocol scheme
|
||||
}
|
||||
|
||||
func ExampleWithCustomBaseURL() {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithCustomBaseURL("https://{account}.{service}.core.windows.net/",
|
||||
map[string]interface{}{
|
||||
"account": "myaccount",
|
||||
"service": "blob",
|
||||
}))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://myaccount.blob.core.windows.net/
|
||||
}
|
||||
|
||||
func ExampleWithCustomBaseURL_second() {
|
||||
_, err := Prepare(&http.Request{},
|
||||
WithCustomBaseURL(":", map[string]interface{}{}))
|
||||
fmt.Println(err)
|
||||
// Output: parse :: missing protocol scheme
|
||||
}
|
||||
|
||||
// Create a request with a custom HTTP header
|
||||
func ExampleWithHeader() {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/a/b/c/"),
|
||||
WithHeader("x-foo", "bar"))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Header %s=%s\n", "x-foo", r.Header.Get("x-foo"))
|
||||
}
|
||||
// Output: Header x-foo=bar
|
||||
}
|
||||
|
||||
// Create a request whose Body is the JSON encoding of a structure
|
||||
func ExampleWithFormData() {
|
||||
v := url.Values{}
|
||||
v.Add("name", "Rob Pike")
|
||||
v.Add("age", "42")
|
||||
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithFormData(v))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Request Body contains %s\n", string(b))
|
||||
}
|
||||
// Output: Request Body contains age=42&name=Rob+Pike
|
||||
}
|
||||
|
||||
// Create a request whose Body is the JSON encoding of a structure
|
||||
func ExampleWithJSON() {
|
||||
t := mocks.T{Name: "Rob Pike", Age: 42}
|
||||
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithJSON(&t))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Request Body contains %s\n", string(b))
|
||||
}
|
||||
// Output: Request Body contains {"name":"Rob Pike","age":42}
|
||||
}
|
||||
|
||||
// Create a request from a path with escaped parameters
|
||||
func ExampleWithEscapedPathParameters() {
|
||||
params := map[string]interface{}{
|
||||
"param1": "a b c",
|
||||
"param2": "d e f",
|
||||
}
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithEscapedPathParameters("/{param1}/b/{param2}/", params))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a+b+c/b/d+e+f/
|
||||
}
|
||||
|
||||
// Create a request from a path with parameters
|
||||
func ExampleWithPathParameters() {
|
||||
params := map[string]interface{}{
|
||||
"param1": "a",
|
||||
"param2": "c",
|
||||
}
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPathParameters("/{param1}/b/{param2}/", params))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c/
|
||||
}
|
||||
|
||||
// Create a request with query parameters
|
||||
func ExampleWithQueryParameters() {
|
||||
params := map[string]interface{}{
|
||||
"q1": "value1",
|
||||
"q2": "value2",
|
||||
}
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBaseURL("https://microsoft.com/"),
|
||||
WithPath("/a/b/c/"),
|
||||
WithQueryParameters(params))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(r.URL)
|
||||
}
|
||||
// Output: https://microsoft.com/a/b/c/?q1=value1&q2=value2
|
||||
}
|
||||
|
||||
func TestWithCustomBaseURL(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{}, WithCustomBaseURL("https://{account}.{service}.core.windows.net/",
|
||||
map[string]interface{}{
|
||||
"account": "myaccount",
|
||||
"service": "blob",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithCustomBaseURL should not fail")
|
||||
}
|
||||
if r.URL.String() != "https://myaccount.blob.core.windows.net/" {
|
||||
t.Fatalf("autorest: WithCustomBaseURL expected https://myaccount.blob.core.windows.net/, got %s", r.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithCustomBaseURLwithInvalidURL(t *testing.T) {
|
||||
_, err := Prepare(&http.Request{}, WithCustomBaseURL("hello/{account}.{service}.core.windows.net/",
|
||||
map[string]interface{}{
|
||||
"account": "myaccount",
|
||||
"service": "blob",
|
||||
}))
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithCustomBaseURL should fail fo URL parse error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithPathWithInvalidPath(t *testing.T) {
|
||||
p := "path%2*end"
|
||||
if _, err := Prepare(&http.Request{}, WithBaseURL("https://microsoft.com/"), WithPath(p)); err == nil {
|
||||
t.Fatalf("autorest: WithPath should fail for invalid URL escape error for path '%v' ", p)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWithPathParametersWithInvalidPath(t *testing.T) {
|
||||
p := "path%2*end"
|
||||
m := map[string]interface{}{
|
||||
"path1": p,
|
||||
}
|
||||
if _, err := Prepare(&http.Request{}, WithBaseURL("https://microsoft.com/"), WithPathParameters("/{path1}/", m)); err == nil {
|
||||
t.Fatalf("autorest: WithPath should fail for invalid URL escape for path '%v' ", p)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCreatePreparerDoesNotModify(t *testing.T) {
|
||||
r1 := &http.Request{}
|
||||
p := CreatePreparer()
|
||||
r2, err := p.Prepare(r1)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: CreatePreparer failed (%v)", err)
|
||||
}
|
||||
if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatalf("autorest: CreatePreparer without decorators modified the request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreatePreparerRunsDecoratorsInOrder(t *testing.T) {
|
||||
p := CreatePreparer(WithBaseURL("https://microsoft.com/"), WithPath("1"), WithPath("2"), WithPath("3"))
|
||||
r, err := p.Prepare(&http.Request{})
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: CreatePreparer failed (%v)", err)
|
||||
}
|
||||
if r.URL.String() != "https:/1/2/3" && r.URL.Host != "microsoft.com" {
|
||||
t.Fatalf("autorest: CreatePreparer failed to run decorators in order")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsContentType(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequest(), AsContentType("application/text"))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v", err)
|
||||
}
|
||||
if r.Header.Get(headerContentType) != "application/text" {
|
||||
t.Fatalf("autorest: AsContentType failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsFormURLEncoded(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequest(), AsFormURLEncoded())
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v", err)
|
||||
}
|
||||
if r.Header.Get(headerContentType) != mimeTypeFormPost {
|
||||
t.Fatalf("autorest: AsFormURLEncoded failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsJSON(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequest(), AsJSON())
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v", err)
|
||||
}
|
||||
if r.Header.Get(headerContentType) != mimeTypeJSON {
|
||||
t.Fatalf("autorest: AsJSON failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithNothing(t *testing.T) {
|
||||
r1 := mocks.NewRequest()
|
||||
r2, err := Prepare(r1, WithNothing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithNothing returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatal("azure: WithNothing modified the passed HTTP Request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithBearerAuthorization(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequest(), WithBearerAuthorization("SOME-TOKEN"))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v", err)
|
||||
}
|
||||
if r.Header.Get(headerAuthorization) != "Bearer SOME-TOKEN" {
|
||||
t.Fatalf("autorest: WithBearerAuthorization failed to add header (%s=%s)", headerAuthorization, r.Header.Get(headerAuthorization))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithUserAgent(t *testing.T) {
|
||||
ua := "User Agent Go"
|
||||
r, err := Prepare(mocks.NewRequest(), WithUserAgent(ua))
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %v", err)
|
||||
}
|
||||
if r.UserAgent() != ua || r.Header.Get(headerUserAgent) != ua {
|
||||
t.Fatalf("autorest: WithUserAgent failed to add header (%s=%s)", headerUserAgent, r.Header.Get(headerUserAgent))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithMethod(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), WithMethod("HEAD"))
|
||||
if r.Method != "HEAD" {
|
||||
t.Fatal("autorest: WithMethod failed to set HTTP method header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsDelete(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsDelete())
|
||||
if r.Method != "DELETE" {
|
||||
t.Fatal("autorest: AsDelete failed to set HTTP method header to DELETE")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsGet(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsGet())
|
||||
if r.Method != "GET" {
|
||||
t.Fatal("autorest: AsGet failed to set HTTP method header to GET")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsHead(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsHead())
|
||||
if r.Method != "HEAD" {
|
||||
t.Fatal("autorest: AsHead failed to set HTTP method header to HEAD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsOptions(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsOptions())
|
||||
if r.Method != "OPTIONS" {
|
||||
t.Fatal("autorest: AsOptions failed to set HTTP method header to OPTIONS")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsPatch(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsPatch())
|
||||
if r.Method != "PATCH" {
|
||||
t.Fatal("autorest: AsPatch failed to set HTTP method header to PATCH")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsPost(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsPost())
|
||||
if r.Method != "POST" {
|
||||
t.Fatal("autorest: AsPost failed to set HTTP method header to POST")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsPut(t *testing.T) {
|
||||
r, _ := Prepare(mocks.NewRequest(), AsPut())
|
||||
if r.Method != "PUT" {
|
||||
t.Fatal("autorest: AsPut failed to set HTTP method header to PUT")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareWithNullRequest(t *testing.T) {
|
||||
_, err := Prepare(nil)
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Prepare failed to return an error when given a null http.Request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithFormData(t *testing.T) {
|
||||
v := url.Values{}
|
||||
v.Add("name", "Rob Pike")
|
||||
v.Add("age", "42")
|
||||
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithFormData(v))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
expected := "name=Rob+Pike&age=42"
|
||||
if !(string(b) == "name=Rob+Pike&age=42" || string(b) == "age=42&name=Rob+Pike") {
|
||||
t.Fatalf("autorest:WithFormData failed to return correct string got (%v), expected (%v)", string(b), expected)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(b)) {
|
||||
t.Fatalf("autorest:WithFormData set Content-Length to %v, expected %v", r.ContentLength, len(b))
|
||||
}
|
||||
|
||||
if expected, got := r.Header.Get(http.CanonicalHeaderKey(headerContentType)), mimeTypeFormPost; expected != got {
|
||||
t.Fatalf("autorest:WithFormData Content Type not set or set to wrong value. Expected %v and got %v", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithMultiPartFormDataSetsContentLength(t *testing.T) {
|
||||
v := map[string]interface{}{
|
||||
"file": ioutil.NopCloser(strings.NewReader("Hello Gopher")),
|
||||
"age": "42",
|
||||
}
|
||||
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithMultiPartFormData(v))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(b)) {
|
||||
t.Fatalf("autorest:WithMultiPartFormData set Content-Length to %v, expected %v", r.ContentLength, len(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithMultiPartFormDataWithNoFile(t *testing.T) {
|
||||
v := map[string]interface{}{
|
||||
"file": "no file",
|
||||
"age": "42",
|
||||
}
|
||||
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithMultiPartFormData(v))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(b)) {
|
||||
t.Fatalf("autorest:WithMultiPartFormData set Content-Length to %v, expected %v", r.ContentLength, len(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithFile(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithFile(ioutil.NopCloser(strings.NewReader("Hello Gopher"))))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFile failed with error (%v)", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFile failed with error (%v)", err)
|
||||
}
|
||||
if r.ContentLength != int64(len(b)) {
|
||||
t.Fatalf("autorest:WithFile set Content-Length to %v, expected %v", r.ContentLength, len(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithBool_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithBool(false))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithBool failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithBool failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(fmt.Sprintf("%v", false))) {
|
||||
t.Fatalf("autorest: WithBool set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", false))))
|
||||
}
|
||||
|
||||
v, err := strconv.ParseBool(string(s))
|
||||
if err != nil || v {
|
||||
t.Fatalf("autorest: WithBool incorrectly encoded the boolean as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithFloat32_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithFloat32(42.0))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFloat32 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFloat32 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(fmt.Sprintf("%v", 42.0))) {
|
||||
t.Fatalf("autorest: WithFloat32 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42.0))))
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(string(s), 32)
|
||||
if err != nil || float32(v) != float32(42.0) {
|
||||
t.Fatalf("autorest: WithFloat32 incorrectly encoded the boolean as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithFloat64_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithFloat64(42.0))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFloat64 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithFloat64 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(fmt.Sprintf("%v", 42.0))) {
|
||||
t.Fatalf("autorest: WithFloat64 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42.0))))
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(string(s), 64)
|
||||
if err != nil || v != float64(42.0) {
|
||||
t.Fatalf("autorest: WithFloat64 incorrectly encoded the boolean as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithInt32_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithInt32(42))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithInt32 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithInt32 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(fmt.Sprintf("%v", 42))) {
|
||||
t.Fatalf("autorest: WithInt32 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42))))
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(string(s), 10, 32)
|
||||
if err != nil || int32(v) != int32(42) {
|
||||
t.Fatalf("autorest: WithInt32 incorrectly encoded the boolean as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithInt64_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithInt64(42))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithInt64 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithInt64 failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(fmt.Sprintf("%v", 42))) {
|
||||
t.Fatalf("autorest: WithInt64 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42))))
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(string(s), 10, 64)
|
||||
if err != nil || v != int64(42) {
|
||||
t.Fatalf("autorest: WithInt64 incorrectly encoded the boolean as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithString_SetsTheBody(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithString("value"))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithString failed with error (%v)", err)
|
||||
}
|
||||
|
||||
s, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithString failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len("value")) {
|
||||
t.Fatalf("autorest: WithString set Content-Length to %v, expected %v", r.ContentLength, int64(len("value")))
|
||||
}
|
||||
|
||||
if string(s) != "value" {
|
||||
t.Fatalf("autorest: WithString incorrectly encoded the string as %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithJSONSetsContentLength(t *testing.T) {
|
||||
r, err := Prepare(&http.Request{},
|
||||
WithJSON(&mocks.T{Name: "Rob Pike", Age: 42}))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithJSON failed with error (%v)", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithJSON failed with error (%v)", err)
|
||||
}
|
||||
|
||||
if r.ContentLength != int64(len(b)) {
|
||||
t.Fatalf("autorest:WithJSON set Content-Length to %v, expected %v", r.ContentLength, len(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithHeaderAllocatesHeaders(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequest(), WithHeader("x-foo", "bar"))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithHeader failed (%v)", err)
|
||||
}
|
||||
if r.Header.Get("x-foo") != "bar" {
|
||||
t.Fatalf("autorest: WithHeader failed to add header (%s=%s)", "x-foo", r.Header.Get("x-foo"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithPathCatchesNilURL(t *testing.T) {
|
||||
_, err := Prepare(&http.Request{}, WithPath("a"))
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithPath failed to catch a nil URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithEscapedPathParametersCatchesNilURL(t *testing.T) {
|
||||
_, err := Prepare(&http.Request{}, WithEscapedPathParameters("", map[string]interface{}{"foo": "bar"}))
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithEscapedPathParameters failed to catch a nil URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithPathParametersCatchesNilURL(t *testing.T) {
|
||||
_, err := Prepare(&http.Request{}, WithPathParameters("", map[string]interface{}{"foo": "bar"}))
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithPathParameters failed to catch a nil URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithQueryParametersCatchesNilURL(t *testing.T) {
|
||||
_, err := Prepare(&http.Request{}, WithQueryParameters(map[string]interface{}{"foo": "bar"}))
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithQueryParameters failed to catch a nil URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyingExistingRequest(t *testing.T) {
|
||||
r, err := Prepare(mocks.NewRequestForURL("https://bing.com"), WithPath("search"), WithQueryParameters(map[string]interface{}{"q": "golang"}))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: Preparing an existing request returned an error (%v)", err)
|
||||
}
|
||||
if r.URL.Host != "bing.com" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the host (%s)", r.URL)
|
||||
}
|
||||
|
||||
if r.URL.Path != "/search" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the path (%s)", r.URL.Path)
|
||||
}
|
||||
|
||||
if r.URL.RawQuery != "q=golang" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the query parameters (%s)", r.URL.RawQuery)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyingRequestWithExistingQueryParameters(t *testing.T) {
|
||||
r, err := Prepare(
|
||||
mocks.NewRequestForURL("https://bing.com"),
|
||||
WithPath("search"),
|
||||
WithQueryParameters(map[string]interface{}{"q": "golang the best"}),
|
||||
WithQueryParameters(map[string]interface{}{"pq": "golang+encoded"}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: Preparing an existing request returned an error (%v)", err)
|
||||
}
|
||||
|
||||
if r.URL.Host != "bing.com" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the host (%s)", r.URL)
|
||||
}
|
||||
|
||||
if r.URL.Path != "/search" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the path (%s)", r.URL.Path)
|
||||
}
|
||||
|
||||
if r.URL.RawQuery != "pq=golang+encoded&q=golang+the+best" {
|
||||
t.Fatalf("autorest: Preparing an existing request failed when setting the query parameters (%s)", r.URL.RawQuery)
|
||||
}
|
||||
}
|
||||
665
vendor/github.com/Azure/go-autorest/autorest/responder_test.go
generated
vendored
665
vendor/github.com/Azure/go-autorest/autorest/responder_test.go
generated
vendored
|
|
@ -1,665 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
func ExampleWithErrorUnlessOK() {
|
||||
r := mocks.NewResponse()
|
||||
r.Request = mocks.NewRequest()
|
||||
|
||||
// Respond and leave the response body open (for a subsequent responder to close)
|
||||
err := Respond(r,
|
||||
WithErrorUnlessOK(),
|
||||
ByDiscardingBody(),
|
||||
ByClosingIfError())
|
||||
|
||||
if err == nil {
|
||||
fmt.Printf("%s of %s returned HTTP 200", r.Request.Method, r.Request.URL)
|
||||
|
||||
// Complete handling the response and close the body
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
// Output: GET of https://microsoft.com/a/b/c/ returned HTTP 200
|
||||
}
|
||||
|
||||
func ExampleByUnmarshallingJSON() {
|
||||
c := `
|
||||
{
|
||||
"name" : "Rob Pike",
|
||||
"age" : 42
|
||||
}
|
||||
`
|
||||
|
||||
type V struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
v := &V{}
|
||||
|
||||
Respond(mocks.NewResponseWithContent(c),
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
|
||||
fmt.Printf("%s is %d years old\n", v.Name, v.Age)
|
||||
// Output: Rob Pike is 42 years old
|
||||
}
|
||||
|
||||
func ExampleByUnmarshallingXML() {
|
||||
c := `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Person>
|
||||
<Name>Rob Pike</Name>
|
||||
<Age>42</Age>
|
||||
</Person>`
|
||||
|
||||
type V struct {
|
||||
Name string `xml:"Name"`
|
||||
Age int `xml:"Age"`
|
||||
}
|
||||
|
||||
v := &V{}
|
||||
|
||||
Respond(mocks.NewResponseWithContent(c),
|
||||
ByUnmarshallingXML(v),
|
||||
ByClosing())
|
||||
|
||||
fmt.Printf("%s is %d years old\n", v.Name, v.Age)
|
||||
// Output: Rob Pike is 42 years old
|
||||
}
|
||||
|
||||
func TestCreateResponderDoesNotModify(t *testing.T) {
|
||||
r1 := mocks.NewResponse()
|
||||
r2 := mocks.NewResponse()
|
||||
p := CreateResponder()
|
||||
err := p.Respond(r1)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: CreateResponder failed (%v)", err)
|
||||
}
|
||||
if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatalf("autorest: CreateResponder without decorators modified the response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateResponderRunsDecoratorsInOrder(t *testing.T) {
|
||||
s := ""
|
||||
|
||||
d := func(n int) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err == nil {
|
||||
s += fmt.Sprintf("%d", n)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
p := CreateResponder(d(1), d(2), d(3))
|
||||
err := p.Respond(&http.Response{})
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: Respond failed (%v)", err)
|
||||
}
|
||||
|
||||
if s != "123" {
|
||||
t.Fatalf("autorest: CreateResponder invoked decorators in an incorrect order; expected '123', received '%s'", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByIgnoring(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(r2 *http.Response) error {
|
||||
r1 := mocks.NewResponse()
|
||||
if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatalf("autorest: ByIgnoring modified the HTTP Response -- received %v, expected %v", r2, r1)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByIgnoring(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestByCopying_Copies(t *testing.T) {
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
err := Respond(r,
|
||||
ByCopying(b),
|
||||
ByUnmarshallingJSON(&mocks.T{}),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByCopying returned an unexpected error -- %v", err)
|
||||
}
|
||||
if b.String() != jsonT {
|
||||
t.Fatalf("autorest: ByCopying failed to copy the bytes read")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByCopying_ReturnsNestedErrors(t *testing.T) {
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
|
||||
r.Body.Close()
|
||||
err := Respond(r,
|
||||
ByCopying(&bytes.Buffer{}),
|
||||
ByUnmarshallingJSON(&mocks.T{}),
|
||||
ByClosing())
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: ByCopying failed to return the expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByCopying_AcceptsNilReponse(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
r.Respond(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByCopying(&bytes.Buffer{}))
|
||||
}
|
||||
|
||||
func TestByCopying_AcceptsNilBody(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
resp.Body = nil
|
||||
r.Respond(resp)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByCopying(&bytes.Buffer{}))
|
||||
}
|
||||
|
||||
func TestByClosing(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
err := Respond(r, ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByClosing failed (%v)", err)
|
||||
}
|
||||
if r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatalf("autorest: ByClosing did not close the response body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByClosingAcceptsNilResponse(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
r.Respond(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestByClosingAcceptsNilBody(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
resp.Body = nil
|
||||
r.Respond(resp)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestByClosingClosesEvenAfterErrors(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
ByClosing())
|
||||
|
||||
if r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatalf("autorest: ByClosing did not close the response body after an error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByClosingClosesReturnsNestedErrors(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
err := Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
ByClosing())
|
||||
|
||||
if err == nil || !reflect.DeepEqual(e, err) {
|
||||
t.Fatalf("autorest: ByClosing failed to return a nested error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByClosingIfErrorAcceptsNilResponse(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
r.Respond(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByClosingIfError())
|
||||
}
|
||||
|
||||
func TestByClosingIfErrorAcceptsNilBody(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
resp.Body = nil
|
||||
r.Respond(resp)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByClosingIfError())
|
||||
}
|
||||
|
||||
func TestByClosingIfErrorClosesIfAnErrorOccurs(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
ByClosingIfError())
|
||||
|
||||
if r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatalf("autorest: ByClosingIfError did not close the response body after an error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByClosingIfErrorDoesNotClosesIfNoErrorOccurs(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
Respond(r,
|
||||
ByClosingIfError())
|
||||
|
||||
if !r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatalf("autorest: ByClosingIfError closed the response body even though no error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByDiscardingBody(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
err := Respond(r,
|
||||
ByDiscardingBody())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByDiscardingBody failed (%v)", err)
|
||||
}
|
||||
buf, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: Reading result of ByDiscardingBody failed (%v)", err)
|
||||
}
|
||||
|
||||
if len(buf) != 0 {
|
||||
t.Logf("autorest: Body was not empty after calling ByDiscardingBody.")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestByDiscardingBodyAcceptsNilResponse(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
r.Respond(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByDiscardingBody())
|
||||
}
|
||||
|
||||
func TestByDiscardingBodyAcceptsNilBody(t *testing.T) {
|
||||
var e error
|
||||
|
||||
r := mocks.NewResponse()
|
||||
|
||||
Respond(r,
|
||||
withErrorRespondDecorator(&e),
|
||||
(func() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
resp.Body.Close()
|
||||
resp.Body = nil
|
||||
r.Respond(resp)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})(),
|
||||
ByDiscardingBody())
|
||||
}
|
||||
|
||||
func TestByUnmarshallingJSON(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByUnmarshallingJSON failed (%v)", err)
|
||||
}
|
||||
if v.Name != "Rob Pike" || v.Age != 42 {
|
||||
t.Fatalf("autorest: ByUnmarshallingJSON failed to properly unmarshal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingJSON_HandlesReadErrors(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
r.Body.(*mocks.Body).Close()
|
||||
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: ByUnmarshallingJSON failed to receive / respond to read error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingJSONIncludesJSONInErrors(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
j := jsonT[0 : len(jsonT)-2]
|
||||
r := mocks.NewResponseWithContent(j)
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err == nil || !strings.Contains(err.Error(), j) {
|
||||
t.Fatalf("autorest: ByUnmarshallingJSON failed to return JSON in error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingJSONEmptyInput(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(``)
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByUnmarshallingJSON failed to return nil in case of empty JSON (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingXML(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(xmlT)
|
||||
err := Respond(r,
|
||||
ByUnmarshallingXML(v),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: ByUnmarshallingXML failed (%v)", err)
|
||||
}
|
||||
if v.Name != "Rob Pike" || v.Age != 42 {
|
||||
t.Fatalf("autorest: ByUnmarshallingXML failed to properly unmarshal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingXML_HandlesReadErrors(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(xmlT)
|
||||
r.Body.(*mocks.Body).Close()
|
||||
|
||||
err := Respond(r,
|
||||
ByUnmarshallingXML(v),
|
||||
ByClosing())
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: ByUnmarshallingXML failed to receive / respond to read error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByUnmarshallingXMLIncludesXMLInErrors(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
x := xmlT[0 : len(xmlT)-2]
|
||||
r := mocks.NewResponseWithContent(x)
|
||||
err := Respond(r,
|
||||
ByUnmarshallingXML(v),
|
||||
ByClosing())
|
||||
if err == nil || !strings.Contains(err.Error(), x) {
|
||||
t.Fatalf("autorest: ByUnmarshallingXML failed to return XML in error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondAcceptsNullResponse(t *testing.T) {
|
||||
err := Respond(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: Respond returned an unexpected error when given a null Response (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCodeOKResponse(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
err := Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) failed on okay response. (%v)", err)
|
||||
}
|
||||
|
||||
if v.Name != "Rob Pike" || v.Age != 42 {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) corrupted the response body of okay response.")
|
||||
}
|
||||
}
|
||||
|
||||
func TesWithErrorUnlessStatusCodeErrorResponse(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
e := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
r.Status = "400 BadRequest"
|
||||
r.StatusCode = http.StatusBadRequest
|
||||
|
||||
err := Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK),
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("autorest: WithErrorUnlessStatusCode(http.StatusOK) did not return error, on a response to a bad request.")
|
||||
}
|
||||
|
||||
var errorRespBody []byte
|
||||
if derr, ok := err.(DetailedError); !ok {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) got wrong error type : %T, expected: DetailedError, on a response to a bad request.", err)
|
||||
} else {
|
||||
errorRespBody = derr.ServiceError
|
||||
}
|
||||
|
||||
if errorRespBody == nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) ServiceError not returned in DetailedError on a response to a bad request.")
|
||||
}
|
||||
|
||||
err = json.Unmarshal(errorRespBody, e)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) cannot parse error returned in ServiceError into json. %v", err)
|
||||
}
|
||||
|
||||
expected := &mocks.T{Name: "Rob Pike", Age: 42}
|
||||
if e != expected {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK wrong value from parsed ServiceError: got=%#v expected=%#v", e, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCode(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
r.Request = mocks.NewRequest()
|
||||
r.Status = "400 BadRequest"
|
||||
r.StatusCode = http.StatusBadRequest
|
||||
|
||||
err := Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError),
|
||||
ByClosingIfError())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode returned an error (%v) for an acceptable status code (%s)", err, r.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessStatusCodeEmitsErrorForUnacceptableStatusCode(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
r.Request = mocks.NewRequest()
|
||||
r.Status = "400 BadRequest"
|
||||
r.StatusCode = http.StatusBadRequest
|
||||
|
||||
err := Respond(r,
|
||||
WithErrorUnlessStatusCode(http.StatusOK, http.StatusUnauthorized, http.StatusInternalServerError),
|
||||
ByClosingIfError())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessStatusCode failed to return an error for an unacceptable status code (%s)", r.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessOK(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
r.Request = mocks.NewRequest()
|
||||
|
||||
err := Respond(r,
|
||||
WithErrorUnlessOK(),
|
||||
ByClosingIfError())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessOK returned an error for OK status code (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithErrorUnlessOKEmitsErrorIfNotOK(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
r.Request = mocks.NewRequest()
|
||||
r.Status = "400 BadRequest"
|
||||
r.StatusCode = http.StatusBadRequest
|
||||
|
||||
err := Respond(r,
|
||||
WithErrorUnlessOK(),
|
||||
ByClosingIfError())
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: WithErrorUnlessOK failed to return an error for a non-OK status code (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHeader(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
v := []string{"v1", "v2", "v3"}
|
||||
mocks.SetResponseHeaderValues(r, mocks.TestHeader, v)
|
||||
|
||||
if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) {
|
||||
t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
|
||||
mocks.TestHeader, v, mocks.TestHeader, ExtractHeader(mocks.TestHeader, r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHeaderHandlesMissingHeader(t *testing.T) {
|
||||
var v []string
|
||||
r := mocks.NewResponse()
|
||||
|
||||
if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) {
|
||||
t.Fatalf("autorest: ExtractHeader failed to handle a missing header -- expected %v, received %v",
|
||||
v, ExtractHeader(mocks.TestHeader, r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHeaderValue(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
v := "v1"
|
||||
mocks.SetResponseHeader(r, mocks.TestHeader, v)
|
||||
|
||||
if ExtractHeaderValue(mocks.TestHeader, r) != v {
|
||||
t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
|
||||
mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHeaderValueHandlesMissingHeader(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
v := ""
|
||||
|
||||
if ExtractHeaderValue(mocks.TestHeader, r) != v {
|
||||
t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
|
||||
mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHeaderValueRetrievesFirstValue(t *testing.T) {
|
||||
r := mocks.NewResponse()
|
||||
v := []string{"v1", "v2", "v3"}
|
||||
mocks.SetResponseHeaderValues(r, mocks.TestHeader, v)
|
||||
|
||||
if ExtractHeaderValue(mocks.TestHeader, r) != v[0] {
|
||||
t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
|
||||
mocks.TestHeader, v[0], mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
|
||||
}
|
||||
}
|
||||
954
vendor/github.com/Azure/go-autorest/autorest/sender_test.go
generated
vendored
954
vendor/github.com/Azure/go-autorest/autorest/sender_test.go
generated
vendored
|
|
@ -1,954 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
func ExampleSendWithSender() {
|
||||
r := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(r)
|
||||
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(r, 10)
|
||||
|
||||
logger := log.New(os.Stdout, "autorest: ", 0)
|
||||
na := NullAuthorizer{}
|
||||
|
||||
req, _ := Prepare(&http.Request{},
|
||||
AsGet(),
|
||||
WithBaseURL("https://microsoft.com/a/b/c/"),
|
||||
na.WithAuthorization())
|
||||
|
||||
r, _ = SendWithSender(client, req,
|
||||
WithLogging(logger),
|
||||
DoErrorIfStatusCode(http.StatusAccepted),
|
||||
DoCloseIfError(),
|
||||
DoRetryForAttempts(5, time.Duration(0)))
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
// Output:
|
||||
// autorest: Sending GET https://microsoft.com/a/b/c/
|
||||
// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
|
||||
// autorest: Sending GET https://microsoft.com/a/b/c/
|
||||
// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
|
||||
// autorest: Sending GET https://microsoft.com/a/b/c/
|
||||
// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
|
||||
// autorest: Sending GET https://microsoft.com/a/b/c/
|
||||
// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
|
||||
// autorest: Sending GET https://microsoft.com/a/b/c/
|
||||
// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
|
||||
}
|
||||
|
||||
func ExampleDoRetryForAttempts() {
|
||||
client := mocks.NewSender()
|
||||
client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10)
|
||||
|
||||
// Retry with backoff -- ensure returned Bodies are closed
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoCloseIfError(),
|
||||
DoRetryForAttempts(5, time.Duration(0)))
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
fmt.Printf("Retry stopped after %d attempts", client.Attempts())
|
||||
// Output: Retry stopped after 5 attempts
|
||||
}
|
||||
|
||||
func ExampleDoErrorIfStatusCode() {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 NoContent", http.StatusNoContent), 10)
|
||||
|
||||
// Chain decorators to retry the request, up to five times, if the status code is 204
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorIfStatusCode(http.StatusNoContent),
|
||||
DoCloseIfError(),
|
||||
DoRetryForAttempts(5, time.Duration(0)))
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
fmt.Printf("Retry stopped after %d attempts with code %s", client.Attempts(), r.Status)
|
||||
// Output: Retry stopped after 5 attempts with code 204 NoContent
|
||||
}
|
||||
|
||||
func TestSendWithSenderRunsDecoratorsInOrder(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
s := ""
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
withMessage(&s, "a"),
|
||||
withMessage(&s, "b"),
|
||||
withMessage(&s, "c"))
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: SendWithSender returned an error (%v)", err)
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if s != "abc" {
|
||||
t.Fatalf("autorest: SendWithSender invoke decorators out of order; expected 'abc', received '%s'", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateSender(t *testing.T) {
|
||||
f := false
|
||||
|
||||
s := CreateSender(
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
s.Do(&http.Request{})
|
||||
|
||||
if !f {
|
||||
t.Fatal("autorest: CreateSender failed to apply supplied decorator")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSend(t *testing.T) {
|
||||
f := false
|
||||
|
||||
Send(&http.Request{},
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
|
||||
if !f {
|
||||
t.Fatal("autorest: Send failed to apply supplied decorator")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterDelayWaits(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
d := 2 * time.Second
|
||||
|
||||
tt := time.Now()
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
AfterDelay(d))
|
||||
s := time.Since(tt)
|
||||
if s < d {
|
||||
t.Fatal("autorest: AfterDelay failed to wait for at least the specified duration")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestAfterDelay_Cancels(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
delay := 5 * time.Second
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
start := time.Now()
|
||||
end := time.Now()
|
||||
var err error
|
||||
go func() {
|
||||
req := mocks.NewRequest()
|
||||
req = req.WithContext(ctx)
|
||||
_, err = SendWithSender(client, req,
|
||||
AfterDelay(delay))
|
||||
end = time.Now()
|
||||
wg.Done()
|
||||
}()
|
||||
cancel()
|
||||
wg.Wait()
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
if end.Sub(start) >= delay {
|
||||
t.Fatal("autorest: AfterDelay elapsed")
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("autorest: AfterDelay didn't cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterDelayDoesNotWaitTooLong(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
d := 5 * time.Millisecond
|
||||
start := time.Now()
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
AfterDelay(d))
|
||||
|
||||
if time.Since(start) > (5 * d) {
|
||||
t.Fatal("autorest: AfterDelay waited too long (exceeded 5 times specified duration)")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestAsIs(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
r1 := mocks.NewResponse()
|
||||
client.AppendResponse(r1)
|
||||
|
||||
r2, err := SendWithSender(client, mocks.NewRequest(),
|
||||
AsIs())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: AsIs returned an unexpected error (%v)", err)
|
||||
} else if !reflect.DeepEqual(r1, r2) {
|
||||
t.Fatalf("autorest: AsIs modified the response -- received %v, expected %v", r2, r1)
|
||||
}
|
||||
|
||||
Respond(r1,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
Respond(r2,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoCloseIfError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorIfStatusCode(http.StatusBadRequest),
|
||||
DoCloseIfError())
|
||||
|
||||
if r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatal("autorest: Expected DoCloseIfError to close response body -- it was left open")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoCloseIfErrorAcceptsNilResponse(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
SendWithSender(client, mocks.NewRequest(),
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("Faux Error")
|
||||
})
|
||||
}
|
||||
})(),
|
||||
DoCloseIfError())
|
||||
}
|
||||
|
||||
func TestDoCloseIfErrorAcceptsNilBody(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
SendWithSender(client, mocks.NewRequest(),
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
resp.Body = nil
|
||||
return resp, fmt.Errorf("Faux Error")
|
||||
})
|
||||
}
|
||||
})(),
|
||||
DoCloseIfError())
|
||||
}
|
||||
|
||||
func TestDoErrorIfStatusCode(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorIfStatusCode(http.StatusBadRequest),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: DoErrorIfStatusCode failed to emit an error for passed code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoErrorIfStatusCodeIgnoresStatusCodes(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(newAcceptedResponse())
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorIfStatusCode(http.StatusBadRequest),
|
||||
DoCloseIfError())
|
||||
if err != nil {
|
||||
t.Fatal("autorest: DoErrorIfStatusCode failed to ignore a status code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoErrorUnlessStatusCode(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorUnlessStatusCode(http.StatusAccepted),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: DoErrorUnlessStatusCode failed to emit an error for an unknown status code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoErrorUnlessStatusCodeIgnoresStatusCodes(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(newAcceptedResponse())
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoErrorUnlessStatusCode(http.StatusAccepted),
|
||||
DoCloseIfError())
|
||||
if err != nil {
|
||||
t.Fatal("autorest: DoErrorUnlessStatusCode emitted an error for a knonwn status code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForAttemptsStopsAfterSuccess(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForAttempts(5, time.Duration(0)))
|
||||
if client.Attempts() != 1 {
|
||||
t.Fatalf("autorest: DoRetryForAttempts failed to stop after success -- expected attempts %v, actual %v",
|
||||
1, client.Attempts())
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: DoRetryForAttempts returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForAttemptsStopsAfterAttempts(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10)
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForAttempts(5, time.Duration(0)),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Mock client failed to emit errors")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if client.Attempts() != 5 {
|
||||
t.Fatal("autorest: DoRetryForAttempts failed to stop after specified number of attempts")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForAttemptsReturnsResponse(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.SetError(fmt.Errorf("Faux Error"))
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForAttempts(1, time.Duration(0)))
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Mock client failed to emit errors")
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
t.Fatal("autorest: DoRetryForAttempts failed to return the underlying response")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForDurationStopsAfterSuccess(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForDuration(10*time.Millisecond, time.Duration(0)))
|
||||
if client.Attempts() != 1 {
|
||||
t.Fatalf("autorest: DoRetryForDuration failed to stop after success -- expected attempts %v, actual %v",
|
||||
1, client.Attempts())
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: DoRetryForDuration returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForDurationStopsAfterDuration(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
|
||||
|
||||
d := 5 * time.Millisecond
|
||||
start := time.Now()
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForDuration(d, time.Duration(0)),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Mock client failed to emit errors")
|
||||
}
|
||||
|
||||
if time.Since(start) < d {
|
||||
t.Fatal("autorest: DoRetryForDuration failed stopped too soon")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForDurationStopsWithinReason(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
|
||||
|
||||
d := 5 * time.Second
|
||||
start := time.Now()
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForDuration(d, time.Duration(0)),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Mock client failed to emit errors")
|
||||
}
|
||||
|
||||
if time.Since(start) > (5 * d) {
|
||||
t.Fatal("autorest: DoRetryForDuration failed stopped soon enough (exceeded 5 times specified duration)")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForDurationReturnsResponse(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForDuration(10*time.Millisecond, time.Duration(0)),
|
||||
DoCloseIfError())
|
||||
if err == nil {
|
||||
t.Fatal("autorest: Mock client failed to emit errors")
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
t.Fatal("autorest: DoRetryForDuration failed to return the underlying response")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDelayForBackoff(t *testing.T) {
|
||||
d := 2 * time.Second
|
||||
start := time.Now()
|
||||
DelayForBackoff(d, 0, nil)
|
||||
if time.Since(start) < d {
|
||||
t.Fatal("autorest: DelayForBackoff did not delay as long as expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelayForBackoff_Cancels(t *testing.T) {
|
||||
cancel := make(chan struct{})
|
||||
delay := 5 * time.Second
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
start := time.Now()
|
||||
go func() {
|
||||
wg.Done()
|
||||
DelayForBackoff(delay, 0, cancel)
|
||||
}()
|
||||
wg.Wait()
|
||||
close(cancel)
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
if time.Since(start) >= delay {
|
||||
t.Fatal("autorest: DelayForBackoff failed to cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelayForBackoffWithinReason(t *testing.T) {
|
||||
d := 5 * time.Second
|
||||
maxCoefficient := 2
|
||||
start := time.Now()
|
||||
DelayForBackoff(d, 0, nil)
|
||||
if time.Since(start) > (time.Duration(maxCoefficient) * d) {
|
||||
|
||||
t.Fatalf("autorest: DelayForBackoff delayed too long (exceeded %d times the specified duration)", maxCoefficient)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_IgnoresUnspecifiedStatusCodes(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Duration(0), time.Duration(0)))
|
||||
|
||||
if client.Attempts() != 1 {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes polled for unspecified status code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_PollsForSpecifiedStatusCodes(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(newAcceptedResponse())
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
|
||||
if client.Attempts() != 2 {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to poll for specified status code")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_CanBeCanceled(t *testing.T) {
|
||||
cancel := make(chan struct{})
|
||||
delay := 5 * time.Second
|
||||
|
||||
r := mocks.NewResponse()
|
||||
mocks.SetAcceptedHeaders(r)
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(r, 100)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
start := time.Now()
|
||||
go func() {
|
||||
wg.Done()
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}()
|
||||
wg.Wait()
|
||||
close(cancel)
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
if time.Since(start) >= delay {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_ClosesAllNonreturnedResponseBodiesWhenPolling(t *testing.T) {
|
||||
resp := newAcceptedResponse()
|
||||
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(resp, 2)
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
|
||||
if resp.Body.(*mocks.Body).IsOpen() || resp.Body.(*mocks.Body).CloseAttempts() < 2 {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes did not close unreturned response bodies")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_LeavesLastResponseBodyOpen(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(newAcceptedResponse())
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
|
||||
if !r.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes did not leave open the body of the last response")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_StopsPollingAfterAnError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(newAcceptedResponse(), 5)
|
||||
client.SetError(fmt.Errorf("Faux Error"))
|
||||
client.SetEmitErrorAfter(1)
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
|
||||
if client.Attempts() > 2 {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to stop polling after receiving an error")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoPollForStatusCodes_ReturnsPollingError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(newAcceptedResponse(), 5)
|
||||
client.SetError(fmt.Errorf("Faux Error"))
|
||||
client.SetEmitErrorAfter(1)
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to return error from polling")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestWithLogging_Logs(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
logger := log.New(buf, "autorest: ", 0)
|
||||
client := mocks.NewSender()
|
||||
|
||||
r, _ := SendWithSender(client, &http.Request{},
|
||||
WithLogging(logger))
|
||||
|
||||
if buf.String() == "" {
|
||||
t.Fatal("autorest: Sender#WithLogging failed to log the request")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestWithLogging_HandlesMissingResponse(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
logger := log.New(buf, "autorest: ", 0)
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(nil)
|
||||
client.SetError(fmt.Errorf("Faux Error"))
|
||||
|
||||
r, err := SendWithSender(client, &http.Request{},
|
||||
WithLogging(logger))
|
||||
|
||||
if r != nil || err == nil {
|
||||
t.Fatal("autorest: Sender#WithLogging returned a valid response -- expecting nil")
|
||||
}
|
||||
if buf.String() == "" {
|
||||
t.Fatal("autorest: Sender#WithLogging failed to log the request for a nil response")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodesWithSuccess(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("408 Request Timeout", http.StatusRequestTimeout), 2)
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(5, time.Duration(2*time.Second), http.StatusRequestTimeout),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if client.Attempts() != 3 {
|
||||
t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ",
|
||||
r.Status, client.Attempts()-1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodesWithNoSuccess(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("504 Gateway Timeout", http.StatusGatewayTimeout), 5)
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(2, time.Duration(2*time.Second), http.StatusGatewayTimeout),
|
||||
)
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if client.Attempts() != 3 {
|
||||
t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: failed stop after %v retry attempts; Want: Stop after 2 retry attempts",
|
||||
client.Attempts()-1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_CodeNotInRetryList(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 1)
|
||||
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if client.Attempts() != 1 || r.Status != "204 No Content" {
|
||||
t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Retry attempts %v for StatusCode %v; Want: 0 attempts for StatusCode 204",
|
||||
client.Attempts(), r.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_RequestBodyReadError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 2)
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequestWithCloseBody(),
|
||||
DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if err == nil || client.Attempts() != 0 {
|
||||
t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Not failed for request body read error; Want: Failed for body read error - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func newAcceptedResponse() *http.Response {
|
||||
resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
|
||||
mocks.SetAcceptedHeaders(resp)
|
||||
return resp
|
||||
}
|
||||
|
||||
func TestDelayWithRetryAfterWithSuccess(t *testing.T) {
|
||||
after, retries := 2, 2
|
||||
totalSecs := after * retries
|
||||
|
||||
client := mocks.NewSender()
|
||||
resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests)
|
||||
mocks.SetResponseHeader(resp, "Retry-After", fmt.Sprintf("%v", after))
|
||||
client.AppendAndRepeatResponse(resp, retries)
|
||||
client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
|
||||
|
||||
d := time.Second * time.Duration(totalSecs)
|
||||
start := time.Now()
|
||||
r, _ := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests),
|
||||
)
|
||||
|
||||
if time.Since(start) < d {
|
||||
t.Fatal("autorest: DelayWithRetryAfter failed stopped too soon")
|
||||
}
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if client.Attempts() != 3 {
|
||||
t.Fatalf("autorest: Sender#DelayWithRetryAfter -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ",
|
||||
r.Status, client.Attempts()-1)
|
||||
}
|
||||
}
|
||||
|
||||
type temporaryError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (te temporaryError) Error() string {
|
||||
return te.message
|
||||
}
|
||||
|
||||
func (te temporaryError) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (te temporaryError) Temporary() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_NilResponseTemporaryError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(nil)
|
||||
client.SetError(temporaryError{message: "faux error"})
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if err != nil || client.Attempts() != 2 {
|
||||
t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseTemporaryError -- Got: non-nil error or wrong number of attempts - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_NilResponseTemporaryError2(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(nil)
|
||||
client.SetError(fmt.Errorf("faux error"))
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if err != nil || client.Attempts() != 2 {
|
||||
t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseTemporaryError2 -- Got: nil error or wrong number of attempts - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type fatalError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (fe fatalError) Error() string {
|
||||
return fe.message
|
||||
}
|
||||
|
||||
func (fe fatalError) Timeout() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fe fatalError) Temporary() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_NilResponseFatalError(t *testing.T) {
|
||||
client := mocks.NewSender()
|
||||
client.AppendResponse(nil)
|
||||
client.SetError(fatalError{"fatal error"})
|
||||
|
||||
r, err := SendWithSender(client, mocks.NewRequest(),
|
||||
DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...),
|
||||
)
|
||||
|
||||
Respond(r,
|
||||
ByDiscardingBody(),
|
||||
ByClosing())
|
||||
|
||||
if err == nil || client.Attempts() > 1 {
|
||||
t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseFatalError -- Got: nil error or wrong number of attempts - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_Cancel429(t *testing.T) {
|
||||
retries := 6
|
||||
client := mocks.NewSender()
|
||||
resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests)
|
||||
client.AppendAndRepeatResponse(resp, retries)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(retries/2)*time.Second)
|
||||
defer cancel()
|
||||
req := mocks.NewRequest().WithContext(ctx)
|
||||
r, err := SendWithSender(client, req,
|
||||
DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests),
|
||||
)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("unexpected nil-error")
|
||||
}
|
||||
if r == nil {
|
||||
t.Fatal("unexpected nil response")
|
||||
}
|
||||
if r.StatusCode != http.StatusTooManyRequests {
|
||||
t.Fatalf("expected status code 429, got: %d", r.StatusCode)
|
||||
}
|
||||
if client.Attempts() >= retries {
|
||||
t.Fatalf("too many attempts: %d", client.Attempts())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoRetryForStatusCodes_Race(t *testing.T) {
|
||||
// cannot use the mock sender as it's not safe for concurrent use
|
||||
s := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
|
||||
defer s.Close()
|
||||
|
||||
sender := DecorateSender(s.Client(),
|
||||
DoRetryForStatusCodes(0, 0, http.StatusRequestTimeout))
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 2; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
req, _ := http.NewRequest(http.MethodGet, s.URL, nil)
|
||||
if _, err := sender.Do(req); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
234
vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go
generated
vendored
234
vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go
generated
vendored
|
|
@ -1,234 +0,0 @@
|
|||
package to
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
v := ""
|
||||
if String(&v) != v {
|
||||
t.Fatalf("to: String failed to return the correct string -- expected %v, received %v",
|
||||
v, String(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringHandlesNil(t *testing.T) {
|
||||
if String(nil) != "" {
|
||||
t.Fatalf("to: String failed to correctly convert nil -- expected %v, received %v",
|
||||
"", String(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringPtr(t *testing.T) {
|
||||
v := ""
|
||||
if *StringPtr(v) != v {
|
||||
t.Fatalf("to: StringPtr failed to return the correct string -- expected %v, received %v",
|
||||
v, *StringPtr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
v := []string{}
|
||||
if out := StringSlice(&v); !reflect.DeepEqual(out, v) {
|
||||
t.Fatalf("to: StringSlice failed to return the correct slice -- expected %v, received %v",
|
||||
v, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSliceHandlesNil(t *testing.T) {
|
||||
if out := StringSlice(nil); out != nil {
|
||||
t.Fatalf("to: StringSlice failed to correctly convert nil -- expected %v, received %v",
|
||||
nil, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSlicePtr(t *testing.T) {
|
||||
v := []string{"a", "b"}
|
||||
if out := StringSlicePtr(v); !reflect.DeepEqual(*out, v) {
|
||||
t.Fatalf("to: StringSlicePtr failed to return the correct slice -- expected %v, received %v",
|
||||
v, *out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringMap(t *testing.T) {
|
||||
msp := map[string]*string{"foo": StringPtr("foo"), "bar": StringPtr("bar"), "baz": StringPtr("baz")}
|
||||
for k, v := range StringMap(msp) {
|
||||
if *msp[k] != v {
|
||||
t.Fatalf("to: StringMap incorrectly converted an entry -- expected [%s]%v, received[%s]%v",
|
||||
k, v, k, *msp[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringMapHandlesNil(t *testing.T) {
|
||||
msp := map[string]*string{"foo": StringPtr("foo"), "bar": nil, "baz": StringPtr("baz")}
|
||||
for k, v := range StringMap(msp) {
|
||||
if msp[k] == nil && v != "" {
|
||||
t.Fatalf("to: StringMap incorrectly converted a nil entry -- expected [%s]%v, received[%s]%v",
|
||||
k, v, k, *msp[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringMapPtr(t *testing.T) {
|
||||
ms := map[string]string{"foo": "foo", "bar": "bar", "baz": "baz"}
|
||||
for k, msp := range *StringMapPtr(ms) {
|
||||
if ms[k] != *msp {
|
||||
t.Fatalf("to: StringMapPtr incorrectly converted an entry -- expected [%s]%v, received[%s]%v",
|
||||
k, ms[k], k, *msp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBool(t *testing.T) {
|
||||
v := false
|
||||
if Bool(&v) != v {
|
||||
t.Fatalf("to: Bool failed to return the correct string -- expected %v, received %v",
|
||||
v, Bool(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolHandlesNil(t *testing.T) {
|
||||
if Bool(nil) != false {
|
||||
t.Fatalf("to: Bool failed to correctly convert nil -- expected %v, received %v",
|
||||
false, Bool(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolPtr(t *testing.T) {
|
||||
v := false
|
||||
if *BoolPtr(v) != v {
|
||||
t.Fatalf("to: BoolPtr failed to return the correct string -- expected %v, received %v",
|
||||
v, *BoolPtr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
v := 0
|
||||
if Int(&v) != v {
|
||||
t.Fatalf("to: Int failed to return the correct string -- expected %v, received %v",
|
||||
v, Int(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntHandlesNil(t *testing.T) {
|
||||
if Int(nil) != 0 {
|
||||
t.Fatalf("to: Int failed to correctly convert nil -- expected %v, received %v",
|
||||
0, Int(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntPtr(t *testing.T) {
|
||||
v := 0
|
||||
if *IntPtr(v) != v {
|
||||
t.Fatalf("to: IntPtr failed to return the correct string -- expected %v, received %v",
|
||||
v, *IntPtr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt32(t *testing.T) {
|
||||
v := int32(0)
|
||||
if Int32(&v) != v {
|
||||
t.Fatalf("to: Int32 failed to return the correct string -- expected %v, received %v",
|
||||
v, Int32(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt32HandlesNil(t *testing.T) {
|
||||
if Int32(nil) != int32(0) {
|
||||
t.Fatalf("to: Int32 failed to correctly convert nil -- expected %v, received %v",
|
||||
0, Int32(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt32Ptr(t *testing.T) {
|
||||
v := int32(0)
|
||||
if *Int32Ptr(v) != v {
|
||||
t.Fatalf("to: Int32Ptr failed to return the correct string -- expected %v, received %v",
|
||||
v, *Int32Ptr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
v := int64(0)
|
||||
if Int64(&v) != v {
|
||||
t.Fatalf("to: Int64 failed to return the correct string -- expected %v, received %v",
|
||||
v, Int64(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64HandlesNil(t *testing.T) {
|
||||
if Int64(nil) != int64(0) {
|
||||
t.Fatalf("to: Int64 failed to correctly convert nil -- expected %v, received %v",
|
||||
0, Int64(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64Ptr(t *testing.T) {
|
||||
v := int64(0)
|
||||
if *Int64Ptr(v) != v {
|
||||
t.Fatalf("to: Int64Ptr failed to return the correct string -- expected %v, received %v",
|
||||
v, *Int64Ptr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32(t *testing.T) {
|
||||
v := float32(0)
|
||||
if Float32(&v) != v {
|
||||
t.Fatalf("to: Float32 failed to return the correct string -- expected %v, received %v",
|
||||
v, Float32(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32HandlesNil(t *testing.T) {
|
||||
if Float32(nil) != float32(0) {
|
||||
t.Fatalf("to: Float32 failed to correctly convert nil -- expected %v, received %v",
|
||||
0, Float32(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32Ptr(t *testing.T) {
|
||||
v := float32(0)
|
||||
if *Float32Ptr(v) != v {
|
||||
t.Fatalf("to: Float32Ptr failed to return the correct string -- expected %v, received %v",
|
||||
v, *Float32Ptr(v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64(t *testing.T) {
|
||||
v := float64(0)
|
||||
if Float64(&v) != v {
|
||||
t.Fatalf("to: Float64 failed to return the correct string -- expected %v, received %v",
|
||||
v, Float64(&v))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64HandlesNil(t *testing.T) {
|
||||
if Float64(nil) != float64(0) {
|
||||
t.Fatalf("to: Float64 failed to correctly convert nil -- expected %v, received %v",
|
||||
0, Float64(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64Ptr(t *testing.T) {
|
||||
v := float64(0)
|
||||
if *Float64Ptr(v) != v {
|
||||
t.Fatalf("to: Float64Ptr failed to return the correct string -- expected %v, received %v",
|
||||
v, *Float64Ptr(v))
|
||||
}
|
||||
}
|
||||
462
vendor/github.com/Azure/go-autorest/autorest/utility_test.go
generated
vendored
462
vendor/github.com/Azure/go-autorest/autorest/utility_test.go
generated
vendored
|
|
@ -1,462 +0,0 @@
|
|||
package autorest
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonT = `
|
||||
{
|
||||
"name":"Rob Pike",
|
||||
"age":42
|
||||
}`
|
||||
xmlT = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Person>
|
||||
<Name>Rob Pike</Name>
|
||||
<Age>42</Age>
|
||||
</Person>`
|
||||
)
|
||||
|
||||
func TestNewDecoderCreatesJSONDecoder(t *testing.T) {
|
||||
d := NewDecoder(EncodedAsJSON, strings.NewReader(jsonT))
|
||||
_, ok := d.(*json.Decoder)
|
||||
if d == nil || !ok {
|
||||
t.Fatal("autorest: NewDecoder failed to create a JSON decoder when requested")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDecoderCreatesXMLDecoder(t *testing.T) {
|
||||
d := NewDecoder(EncodedAsXML, strings.NewReader(xmlT))
|
||||
_, ok := d.(*xml.Decoder)
|
||||
if d == nil || !ok {
|
||||
t.Fatal("autorest: NewDecoder failed to create an XML decoder when requested")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDecoderReturnsNilForUnknownEncoding(t *testing.T) {
|
||||
d := NewDecoder("unknown", strings.NewReader(xmlT))
|
||||
if d != nil {
|
||||
t.Fatal("autorest: NewDecoder created a decoder for an unknown encoding")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyAndDecodeDecodesJSON(t *testing.T) {
|
||||
_, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{})
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: CopyAndDecode returned an error with valid JSON - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyAndDecodeDecodesXML(t *testing.T) {
|
||||
_, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT), &mocks.T{})
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: CopyAndDecode returned an error with valid XML - %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyAndDecodeReturnsJSONDecodingErrors(t *testing.T) {
|
||||
_, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT[0:len(jsonT)-2]), &mocks.T{})
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid JSON")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyAndDecodeReturnsXMLDecodingErrors(t *testing.T) {
|
||||
_, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT[0:len(xmlT)-2]), &mocks.T{})
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid XML")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyAndDecodeAlwaysReturnsACopy(t *testing.T) {
|
||||
b, _ := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{})
|
||||
if b.String() != jsonT {
|
||||
t.Fatalf("autorest: CopyAndDecode failed to return a valid copy of the data - %v", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeeReadCloser_Copies(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
r.Body = TeeReadCloser(r.Body, b)
|
||||
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err)
|
||||
}
|
||||
if b.String() != jsonT {
|
||||
t.Fatalf("autorest: TeeReadCloser failed to copy the bytes read")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeeReadCloser_PassesReadErrors(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
|
||||
r.Body.(*mocks.Body).Close()
|
||||
r.Body = TeeReadCloser(r.Body, &bytes.Buffer{})
|
||||
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err == nil {
|
||||
t.Fatalf("autorest: TeeReadCloser failed to return the expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeeReadCloser_ClosesWrappedReader(t *testing.T) {
|
||||
v := &mocks.T{}
|
||||
r := mocks.NewResponseWithContent(jsonT)
|
||||
|
||||
b := r.Body.(*mocks.Body)
|
||||
r.Body = TeeReadCloser(r.Body, &bytes.Buffer{})
|
||||
err := Respond(r,
|
||||
ByUnmarshallingJSON(v),
|
||||
ByClosing())
|
||||
if err != nil {
|
||||
t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err)
|
||||
}
|
||||
if b.IsOpen() {
|
||||
t.Fatalf("autorest: TeeReadCloser failed to close the nested io.ReadCloser")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsIntFindsValue(t *testing.T) {
|
||||
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
v := 5
|
||||
if !containsInt(ints, v) {
|
||||
t.Fatalf("autorest: containsInt failed to find %v in %v", v, ints)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsIntDoesNotFindValue(t *testing.T) {
|
||||
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
v := 42
|
||||
if containsInt(ints, v) {
|
||||
t.Fatalf("autorest: containsInt unexpectedly found %v in %v", v, ints)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsIntAcceptsEmptyList(t *testing.T) {
|
||||
ints := make([]int, 10)
|
||||
if containsInt(ints, 42) {
|
||||
t.Fatalf("autorest: containsInt failed to handle an empty list")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsIntAcceptsNilList(t *testing.T) {
|
||||
var ints []int
|
||||
if containsInt(ints, 42) {
|
||||
t.Fatalf("autorest: containsInt failed to handle an nil list")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEscapeStrings(t *testing.T) {
|
||||
m := map[string]string{
|
||||
"string": "a long string with = odd characters",
|
||||
"int": "42",
|
||||
"nil": "",
|
||||
}
|
||||
r := map[string]string{
|
||||
"string": "a+long+string+with+%3D+odd+characters",
|
||||
"int": "42",
|
||||
"nil": "",
|
||||
}
|
||||
v := escapeValueStrings(m)
|
||||
if !reflect.DeepEqual(v, r) {
|
||||
t.Fatalf("autorest: ensureValueStrings returned %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureStrings(t *testing.T) {
|
||||
m := map[string]interface{}{
|
||||
"string": "string",
|
||||
"int": 42,
|
||||
"nil": nil,
|
||||
"bytes": []byte{255, 254, 253},
|
||||
}
|
||||
r := map[string]string{
|
||||
"string": "string",
|
||||
"int": "42",
|
||||
"nil": "",
|
||||
"bytes": string([]byte{255, 254, 253}),
|
||||
}
|
||||
v := ensureValueStrings(m)
|
||||
if !reflect.DeepEqual(v, r) {
|
||||
t.Fatalf("autorest: ensureValueStrings returned %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleString() {
|
||||
m := []string{
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
}
|
||||
|
||||
fmt.Println(String(m, ","))
|
||||
// Output: string1,string2,string3
|
||||
}
|
||||
|
||||
func TestStringWithValidString(t *testing.T) {
|
||||
i := 123
|
||||
if got, want := String(i), "123"; got != want {
|
||||
t.Logf("got: %q\nwant: %q", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWithStringSlice(t *testing.T) {
|
||||
s := []string{"string1", "string2"}
|
||||
if got, want := String(s, ","), "string1,string2"; got != want {
|
||||
t.Logf("got: %q\nwant: %q", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWithEnum(t *testing.T) {
|
||||
type TestEnumType string
|
||||
s := TestEnumType("string1")
|
||||
if got, want := String(s), "string1"; got != want {
|
||||
t.Logf("got: %q\nwant: %q", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWithEnumSlice(t *testing.T) {
|
||||
type TestEnumType string
|
||||
s := []TestEnumType{"string1", "string2"}
|
||||
if got, want := String(s, ","), "string1,string2"; got != want {
|
||||
t.Logf("got: %q\nwant: %q", got, want)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleAsStringSlice() {
|
||||
type TestEnumType string
|
||||
|
||||
a := []TestEnumType{"value1", "value2"}
|
||||
b, _ := AsStringSlice(a)
|
||||
for _, c := range b {
|
||||
fmt.Println(c)
|
||||
}
|
||||
// Output:
|
||||
// value1
|
||||
// value2
|
||||
}
|
||||
|
||||
func TestEncodeWithValidPath(t *testing.T) {
|
||||
s := Encode("Path", "Hello Gopher")
|
||||
if s != "Hello%20Gopher" {
|
||||
t.Fatalf("autorest: Encode method failed for valid path encoding. Got: %v; Want: %v", s, "Hello%20Gopher")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeWithValidQuery(t *testing.T) {
|
||||
s := Encode("Query", "Hello Gopher")
|
||||
if s != "Hello+Gopher" {
|
||||
t.Fatalf("autorest: Encode method failed for valid query encoding. Got: '%v'; Want: 'Hello+Gopher'", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeWithValidNotPathQuery(t *testing.T) {
|
||||
s := Encode("Host", "Hello Gopher")
|
||||
if s != "Hello Gopher" {
|
||||
t.Fatalf("autorest: Encode method failed for parameter not query or path. Got: '%v'; Want: 'Hello Gopher'", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapToValues(t *testing.T) {
|
||||
m := map[string]interface{}{
|
||||
"a": "a",
|
||||
"b": 2,
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Add("a", "a")
|
||||
v.Add("b", "2")
|
||||
if !isEqual(v, MapToValues(m)) {
|
||||
t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapToValuesWithArrayValues(t *testing.T) {
|
||||
m := map[string]interface{}{
|
||||
"a": []string{"a", "b"},
|
||||
"b": 2,
|
||||
"c": []int{3, 4},
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Add("a", "a")
|
||||
v.Add("a", "b")
|
||||
v.Add("b", "2")
|
||||
v.Add("c", "3")
|
||||
v.Add("c", "4")
|
||||
|
||||
if !isEqual(v, MapToValues(m)) {
|
||||
t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m))
|
||||
}
|
||||
}
|
||||
|
||||
type someTempError struct{}
|
||||
|
||||
func (s someTempError) Error() string {
|
||||
return "temporary error"
|
||||
}
|
||||
func (s someTempError) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
func (s someTempError) Temporary() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestIsTemporaryNetworkErrorTrue(t *testing.T) {
|
||||
if !IsTemporaryNetworkError(someTempError{}) {
|
||||
t.Fatal("expected someTempError to be a temporary network error")
|
||||
}
|
||||
if !IsTemporaryNetworkError(errors.New("non-temporary network error")) {
|
||||
t.Fatal("expected random error to be a temporary network error")
|
||||
}
|
||||
}
|
||||
|
||||
type someFatalError struct{}
|
||||
|
||||
func (s someFatalError) Error() string {
|
||||
return "fatal error"
|
||||
}
|
||||
func (s someFatalError) Timeout() bool {
|
||||
return false
|
||||
}
|
||||
func (s someFatalError) Temporary() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func TestIsTemporaryNetworkErrorFalse(t *testing.T) {
|
||||
if IsTemporaryNetworkError(someFatalError{}) {
|
||||
t.Fatal("expected someFatalError to be a fatal network error")
|
||||
}
|
||||
}
|
||||
|
||||
func isEqual(v, u url.Values) bool {
|
||||
for key, value := range v {
|
||||
if len(u[key]) == 0 {
|
||||
return false
|
||||
}
|
||||
sort.Strings(value)
|
||||
sort.Strings(u[key])
|
||||
for i := range value {
|
||||
if value[i] != u[key][i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
u.Del(key)
|
||||
}
|
||||
if len(u) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func doEnsureBodyClosed(t *testing.T) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if resp != nil && resp.Body != nil && resp.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatal("autorest: Expected Body to be closed -- it was left open")
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockAuthorizer struct{}
|
||||
|
||||
func (ma mockAuthorizer) WithAuthorization() PrepareDecorator {
|
||||
return WithHeader(headerAuthorization, mocks.TestAuthorizationHeader)
|
||||
}
|
||||
|
||||
type mockFailingAuthorizer struct{}
|
||||
|
||||
func (mfa mockFailingAuthorizer) WithAuthorization() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockInspector struct {
|
||||
wasInvoked bool
|
||||
}
|
||||
|
||||
func (mi *mockInspector) WithInspection() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
mi.wasInvoked = true
|
||||
return p.Prepare(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (mi *mockInspector) ByInspecting() RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
mi.wasInvoked = true
|
||||
return r.Respond(resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func withMessage(output *string, msg string) SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := s.Do(r)
|
||||
if err == nil {
|
||||
*output += msg
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func withErrorRespondDecorator(e *error) RespondDecorator {
|
||||
return func(r Responder) Responder {
|
||||
return ResponderFunc(func(resp *http.Response) error {
|
||||
err := r.Respond(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = fmt.Errorf("autorest: Faux Respond Error")
|
||||
return *e
|
||||
})
|
||||
}
|
||||
}
|
||||
2450
vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go
generated
vendored
2450
vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
185
vendor/github.com/Azure/go-autorest/logger/logger_test.go
generated
vendored
185
vendor/github.com/Azure/go-autorest/logger/logger_test.go
generated
vendored
|
|
@ -1,185 +0,0 @@
|
|||
package logger
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNilLogger(t *testing.T) {
|
||||
// verify no crash with no logging
|
||||
Instance.WriteRequest(nil, Filter{})
|
||||
}
|
||||
|
||||
const (
|
||||
reqURL = "https://fakething/dot/com"
|
||||
reqHeaderKey = "x-header"
|
||||
reqHeaderVal = "value"
|
||||
reqBody = "the request body"
|
||||
respHeaderKey = "response-header"
|
||||
respHeaderVal = "something"
|
||||
respBody = "the response body"
|
||||
logFileTimeStampRegex = `\(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{7}(-\d{2}:\d{2}|Z)\)`
|
||||
)
|
||||
|
||||
func TestLogReqRespNoBody(t *testing.T) {
|
||||
err := os.Setenv("AZURE_GO_SDK_LOG_LEVEL", "info")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set log level: %v", err)
|
||||
}
|
||||
lf := path.Join(os.TempDir(), "testloggingbasic.log")
|
||||
err = os.Setenv("AZURE_GO_SDK_LOG_FILE", lf)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set log file: %v", err)
|
||||
}
|
||||
initDefaultLogger()
|
||||
if Level() != LogInfo {
|
||||
t.Fatalf("wrong log level: %d", Level())
|
||||
}
|
||||
// create mock request and response for logging
|
||||
req, err := http.NewRequest(http.MethodGet, reqURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create mock request: %v", err)
|
||||
}
|
||||
req.Header.Add(reqHeaderKey, reqHeaderVal)
|
||||
Instance.WriteRequest(req, Filter{})
|
||||
resp := &http.Response{
|
||||
Status: "200 OK",
|
||||
StatusCode: 200,
|
||||
Proto: "HTTP/1.0",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 0,
|
||||
Request: req,
|
||||
Header: http.Header{},
|
||||
}
|
||||
resp.Header.Add(respHeaderKey, respHeaderVal)
|
||||
Instance.WriteResponse(resp, Filter{})
|
||||
if fl, ok := Instance.(fileLogger); ok {
|
||||
fl.logFile.Close()
|
||||
} else {
|
||||
t.Fatal("expected Instance to be fileLogger")
|
||||
}
|
||||
// parse log file to ensure contents match
|
||||
b, err := ioutil.ReadFile(lf)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read log file: %v", err)
|
||||
}
|
||||
parts := strings.Split(string(b), "\n")
|
||||
reqMatch := fmt.Sprintf("%s INFO: REQUEST: %s %s", logFileTimeStampRegex, req.Method, req.URL.String())
|
||||
respMatch := fmt.Sprintf("%s INFO: RESPONSE: %d %s", logFileTimeStampRegex, resp.StatusCode, resp.Request.URL.String())
|
||||
if !matchRegex(t, reqMatch, parts[0]) {
|
||||
t.Fatalf("request header doesn't match: %s", parts[0])
|
||||
}
|
||||
if !matchRegex(t, fmt.Sprintf("(?i)%s: %s", reqHeaderKey, reqHeaderVal), parts[1]) {
|
||||
t.Fatalf("request header entry doesn't match: %s", parts[1])
|
||||
}
|
||||
if !matchRegex(t, respMatch, parts[2]) {
|
||||
t.Fatalf("response header doesn't match: %s", parts[2])
|
||||
}
|
||||
if !matchRegex(t, fmt.Sprintf("(?i)%s: %s", respHeaderKey, respHeaderVal), parts[3]) {
|
||||
t.Fatalf("response header value doesn't match: %s", parts[3])
|
||||
}
|
||||
// disable logging
|
||||
err = os.Setenv("AZURE_GO_SDK_LOG_LEVEL", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to clear log level: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogReqRespWithBody(t *testing.T) {
|
||||
err := os.Setenv("AZURE_GO_SDK_LOG_LEVEL", "debug")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set log level: %v", err)
|
||||
}
|
||||
lf := path.Join(os.TempDir(), "testloggingfull.log")
|
||||
err = os.Setenv("AZURE_GO_SDK_LOG_FILE", lf)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set log file: %v", err)
|
||||
}
|
||||
initDefaultLogger()
|
||||
if Level() != LogDebug {
|
||||
t.Fatalf("wrong log level: %d", Level())
|
||||
}
|
||||
// create mock request and response for logging
|
||||
req, err := http.NewRequest(http.MethodGet, reqURL, strings.NewReader(reqBody))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create mock request: %v", err)
|
||||
}
|
||||
req.Header.Add(reqHeaderKey, reqHeaderVal)
|
||||
Instance.WriteRequest(req, Filter{})
|
||||
resp := &http.Response{
|
||||
Status: "200 OK",
|
||||
StatusCode: 200,
|
||||
Proto: "HTTP/1.0",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 0,
|
||||
Request: req,
|
||||
Header: http.Header{},
|
||||
Body: ioutil.NopCloser(strings.NewReader(respBody)),
|
||||
}
|
||||
resp.Header.Add(respHeaderKey, respHeaderVal)
|
||||
Instance.WriteResponse(resp, Filter{})
|
||||
if fl, ok := Instance.(fileLogger); ok {
|
||||
fl.logFile.Close()
|
||||
} else {
|
||||
t.Fatal("expected Instance to be fileLogger")
|
||||
}
|
||||
// parse log file to ensure contents match
|
||||
b, err := ioutil.ReadFile(lf)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read log file: %v", err)
|
||||
}
|
||||
parts := strings.Split(string(b), "\n")
|
||||
reqMatch := fmt.Sprintf("%s INFO: REQUEST: %s %s", logFileTimeStampRegex, req.Method, req.URL.String())
|
||||
respMatch := fmt.Sprintf("%s INFO: RESPONSE: %d %s", logFileTimeStampRegex, resp.StatusCode, resp.Request.URL.String())
|
||||
if !matchRegex(t, reqMatch, parts[0]) {
|
||||
t.Fatalf("request header doesn't match: %s", parts[0])
|
||||
}
|
||||
if !matchRegex(t, fmt.Sprintf("(?i)%s: %s", reqHeaderKey, reqHeaderVal), parts[1]) {
|
||||
t.Fatalf("request header value doesn't match: %s", parts[1])
|
||||
}
|
||||
if !matchRegex(t, reqBody, parts[2]) {
|
||||
t.Fatalf("request body doesn't match: %s", parts[2])
|
||||
}
|
||||
if !matchRegex(t, respMatch, parts[3]) {
|
||||
t.Fatalf("response header doesn't match: %s", parts[3])
|
||||
}
|
||||
if !matchRegex(t, fmt.Sprintf("(?i)%s: %s", respHeaderKey, respHeaderVal), parts[4]) {
|
||||
t.Fatalf("response header value doesn't match: %s", parts[4])
|
||||
}
|
||||
if !matchRegex(t, respBody, parts[5]) {
|
||||
t.Fatalf("response body doesn't match: %s", parts[5])
|
||||
}
|
||||
// disable logging
|
||||
err = os.Setenv("AZURE_GO_SDK_LOG_LEVEL", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to clear log level: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func matchRegex(t *testing.T, pattern, s string) bool {
|
||||
match, err := regexp.MatchString(pattern, s)
|
||||
if err != nil {
|
||||
t.Fatalf("regexp failure: %v", err)
|
||||
}
|
||||
return match
|
||||
}
|
||||
155
vendor/github.com/Azure/go-autorest/tracing/tracing_test.go
generated
vendored
155
vendor/github.com/Azure/go-autorest/tracing/tracing_test.go
generated
vendored
|
|
@ -1,155 +0,0 @@
|
|||
package tracing
|
||||
|
||||
// Copyright 2018 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/ocagent"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func TestNoTracingByDefault(t *testing.T) {
|
||||
if expected, got := false, IsEnabled(); expected != got {
|
||||
t.Fatalf("By default expected %t, got %t", expected, got)
|
||||
}
|
||||
|
||||
if sampler == nil {
|
||||
t.Fatal("By default expected non nil sampler")
|
||||
}
|
||||
|
||||
if Transport.GetStartOptions(&http.Request{}).Sampler == nil {
|
||||
t.Fatalf("By default expected configured Sampler to be non-nil")
|
||||
}
|
||||
|
||||
for n := range views {
|
||||
v := view.Find(n)
|
||||
if v != nil {
|
||||
t.Fatalf("By default expected no registered views, found %s", v.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableTracing(t *testing.T) {
|
||||
err := Enable()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Enable failed, got error %v", err)
|
||||
}
|
||||
if !IsEnabled() {
|
||||
t.Fatalf("Enable failed, IsEnabled() is %t", IsEnabled())
|
||||
}
|
||||
if sampler != nil {
|
||||
t.Fatalf("Enable failed, expected nil sampler, got %v", sampler)
|
||||
}
|
||||
|
||||
if Transport.GetStartOptions(&http.Request{}).Sampler != nil {
|
||||
t.Fatalf("Enable failed, expected Transport.GetStartOptions.Sampler to be nil")
|
||||
}
|
||||
|
||||
for n, v := range views {
|
||||
fv := view.Find(n)
|
||||
if fv == nil || !reflect.DeepEqual(v, fv) {
|
||||
t.Fatalf("Enable failed, view %s was not registered", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracingByEnv(t *testing.T) {
|
||||
os.Setenv("AZURE_SDK_TRACING_ENABLED", "")
|
||||
enableFromEnv()
|
||||
if !IsEnabled() {
|
||||
t.Fatalf("Enable failed, IsEnabled() is %t", IsEnabled())
|
||||
}
|
||||
if sampler != nil {
|
||||
t.Fatalf("Enable failed, expected nil sampler, got %v", sampler)
|
||||
}
|
||||
|
||||
if Transport.GetStartOptions(&http.Request{}).Sampler != nil {
|
||||
t.Fatalf("Enable failed, expected Transport.GetStartOptions.Sampler to be nil")
|
||||
}
|
||||
|
||||
for n, v := range views {
|
||||
fv := view.Find(n)
|
||||
if fv == nil || !reflect.DeepEqual(v, fv) {
|
||||
t.Fatalf("Enable failed, view %s was not registered", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableTracingWithAIError(t *testing.T) {
|
||||
agentEndpoint := fmt.Sprintf("%s:%d", ocagent.DefaultAgentHost, ocagent.DefaultAgentPort)
|
||||
err := EnableWithAIForwarding(agentEndpoint)
|
||||
if !IsEnabled() {
|
||||
t.Fatalf("Enable failed, IsEnabled() is %t", IsEnabled())
|
||||
}
|
||||
if sampler != nil {
|
||||
t.Fatalf("Enable failed, expected nil sampler, got %v", sampler)
|
||||
}
|
||||
|
||||
if Transport.GetStartOptions(&http.Request{}).Sampler != nil {
|
||||
t.Fatalf("Enable failed, expected Transport.GetStartOptions.Sampler to be nil")
|
||||
}
|
||||
|
||||
for n, v := range views {
|
||||
fv := view.Find(n)
|
||||
if fv == nil || !reflect.DeepEqual(v, fv) {
|
||||
t.Fatalf("Enable failed, view %s was not registered", n)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Expected error on no agent running, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableTracing(t *testing.T) {
|
||||
Enable()
|
||||
Disable()
|
||||
if expected, got := false, IsEnabled(); expected != got {
|
||||
t.Fatalf("By default expected %t, got %t", expected, got)
|
||||
}
|
||||
|
||||
if sampler == nil {
|
||||
t.Fatal("By default expected non nil sampler")
|
||||
}
|
||||
|
||||
if Transport.GetStartOptions(&http.Request{}).Sampler == nil {
|
||||
t.Fatalf("By default expected configured Sampler to be non-nil")
|
||||
}
|
||||
|
||||
for n := range views {
|
||||
v := view.Find(n)
|
||||
if v != nil {
|
||||
t.Fatalf("By default expected no registered views, found %s", v.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartSpan(t *testing.T) {
|
||||
ctx := StartSpan(context.Background(), "testSpan")
|
||||
defer EndSpan(ctx, 200, nil)
|
||||
|
||||
span := trace.FromContext(ctx)
|
||||
if span == nil {
|
||||
t.Fatal("StartSpan failed, expected non-nil span")
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/census-instrumentation/opencensus-proto/CONTRIBUTING.md
generated
vendored
26
vendor/github.com/census-instrumentation/opencensus-proto/CONTRIBUTING.md
generated
vendored
|
|
@ -1,26 +0,0 @@
|
|||
# How to submit a bug report
|
||||
|
||||
If you received an error message, please include it and any exceptions.
|
||||
|
||||
We commonly need to know which language you are using (e.g. Java) and what
|
||||
platform you are on:
|
||||
* Operating system (i.e., ```uname -a```)
|
||||
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contributions to Census! Here are some
|
||||
guideline and information about how to do so.
|
||||
|
||||
## Before getting started
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
We follow the [Google Proto Style Guide](
|
||||
https://developers.google.com/protocol-buffers/docs/style).
|
||||
|
||||
## Proposing changes
|
||||
|
||||
Make sure that `bazel build :all` completes successfully without any new warnings.
|
||||
Then create a Pull Request with your changes. When the changes are accepted, they
|
||||
will be merged or cherry-picked by a Census core developer.
|
||||
80
vendor/github.com/census-instrumentation/opencensus-proto/README.md
generated
vendored
80
vendor/github.com/census-instrumentation/opencensus-proto/README.md
generated
vendored
|
|
@ -1,80 +0,0 @@
|
|||
OpenCensus Proto - Language Independent Interface Types For OpenCensus
|
||||
===============================================================
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Maven Central][maven-image]][maven-url]
|
||||
|
||||
Census provides a framework to define and collect stats against metrics and to
|
||||
break those stats down across user-defined dimensions.
|
||||
|
||||
The Census framework is natively available in many languages (e.g. C++, Go,
|
||||
and Java). The API interface types are defined using protos to ensure
|
||||
consistency and interoperability for the different implementations.
|
||||
|
||||
## Quickstart
|
||||
|
||||
### Install to Go
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/census-instrumentation/opencensus-proto
|
||||
```
|
||||
|
||||
In most cases you should depend on the gen-go files directly. If you are
|
||||
building with Bazel, there are also go_proto_library build rules available.
|
||||
See [PR/132](https://github.com/census-instrumentation/opencensus-proto/pull/132)
|
||||
for details. However, please note that Bazel doesn't generate the final
|
||||
artifacts.
|
||||
|
||||
### Add the dependencies to your Java project
|
||||
|
||||
For Maven add to `pom.xml`:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.opencensus</groupId>
|
||||
<artifactId>opencensus-proto</artifactId>
|
||||
<version>0.0.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
For Gradle add to dependencies:
|
||||
```gradle
|
||||
compile 'io.opencensus:opencensus-proto:0.0.2'
|
||||
```
|
||||
|
||||
[travis-image]: https://travis-ci.org/census-instrumentation/opencensus-proto.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/census-instrumentation/opencensus-proto
|
||||
[maven-image]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-proto/badge.svg
|
||||
[maven-url]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-proto
|
||||
|
||||
### Add the dependencies to Bazel project
|
||||
|
||||
In WORKSPACE, add:
|
||||
```
|
||||
git_repository(
|
||||
name = "io_opencensus_proto",
|
||||
strip_prefix = "src",
|
||||
tag = "v0.0.2", # CURRENT_OPENCENSUS_PROTO_VERSION
|
||||
remote = "https://github.com/census-instrumentation/opencensus-proto",
|
||||
)
|
||||
```
|
||||
or
|
||||
|
||||
```
|
||||
http_archive(
|
||||
name = "io_opencensus_proto",
|
||||
strip_prefix = "opencensus-proto-master/src",
|
||||
urls = ["https://github.com/census-instrumentation/opencensus-proto/archive/master.zip"],
|
||||
)
|
||||
```
|
||||
|
||||
In BUILD.bazel:
|
||||
```bazel
|
||||
proto_library(
|
||||
name = "foo_proto",
|
||||
srcs = ["foo.proto"],
|
||||
deps = [
|
||||
"@io_opencensus_proto//opencensus/proto/metrics/v1:metrics_proto",
|
||||
"@io_opencensus_proto//opencensus/proto/trace/v1:trace_proto",
|
||||
# etc.
|
||||
],
|
||||
)
|
||||
```
|
||||
190
vendor/github.com/census-instrumentation/opencensus-proto/RELEASING.md
generated
vendored
190
vendor/github.com/census-instrumentation/opencensus-proto/RELEASING.md
generated
vendored
|
|
@ -1,190 +0,0 @@
|
|||
# How to Create a Release of OpenCensus Proto (for Maintainers Only)
|
||||
|
||||
## Build Environments
|
||||
|
||||
We re-generate gen-go files and deploy jars to Maven Central under the following systems:
|
||||
|
||||
- Ubuntu 14.04
|
||||
|
||||
Other systems may also work, but we haven't verified them.
|
||||
|
||||
## Release Go files
|
||||
|
||||
To generate the Go files from protos, you'll need to install protoc and protoc-gen-go plugin first.
|
||||
Follow the instructions [here](http://google.github.io/proto-lens/installing-protoc.html) and
|
||||
[here](https://github.com/golang/protobuf#installation).
|
||||
|
||||
Then run the following commands to re-generate the gen-go files:
|
||||
|
||||
```bash
|
||||
$ cd $(go env GOPATH)/src/github.com/census-instrumentation/opencensus-proto
|
||||
$ git checkout -b update-gen-go
|
||||
$ rm -rf gen-go
|
||||
$ cd src
|
||||
$ ./mkgogen.sh
|
||||
$ git add -A
|
||||
$ git commit -m "Update gen-go files."
|
||||
```
|
||||
|
||||
Go through PR review and merge the changes to GitHub.
|
||||
|
||||
## Tagging the Release
|
||||
|
||||
Our release branches follow the naming convention of `v<major>.<minor>.x`, while the tags include the
|
||||
patch version `v<major>.<minor>.<patch>`. For example, the same branch `v0.4.x` would be used to create
|
||||
all `v0.4` tags (e.g. `v0.4.0`, `v0.4.1`).
|
||||
|
||||
In this section upstream repository refers to the main opencensus-proto github
|
||||
repository.
|
||||
|
||||
Before any push to the upstream repository you need to create a [personal access
|
||||
token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/).
|
||||
|
||||
1. Create the release branch and push it to GitHub:
|
||||
|
||||
```bash
|
||||
$ MAJOR=0 MINOR=4 PATCH=0 # Set appropriately for new release
|
||||
$ VERSION_FILES=(
|
||||
build.gradle
|
||||
pom.xml
|
||||
)
|
||||
$ git checkout -b v$MAJOR.$MINOR.x master
|
||||
$ git push upstream v$MAJOR.$MINOR.x
|
||||
```
|
||||
|
||||
2. Enable branch protection for the new branch, if you have admin access.
|
||||
Otherwise, let someone with admin access know that there is a new release
|
||||
branch.
|
||||
|
||||
- Open the branch protection settings for the new branch, by following
|
||||
[Github's instructions](https://help.github.com/articles/configuring-protected-branches/).
|
||||
- Copy the settings from a previous branch, i.e., check
|
||||
- `Protect this branch`
|
||||
- `Require pull request reviews before merging`
|
||||
- `Require status checks to pass before merging`
|
||||
- `Include administrators`
|
||||
|
||||
Enable the following required status checks:
|
||||
- `cla/google`
|
||||
- `continuous-integration/travis-ci`
|
||||
- Uncheck everything else.
|
||||
- Click "Save changes".
|
||||
|
||||
3. For `master` branch:
|
||||
|
||||
- Change root build files to the next minor snapshot (e.g.
|
||||
`0.5.0-SNAPSHOT`).
|
||||
|
||||
```bash
|
||||
$ git checkout -b bump-version master
|
||||
# Change version to next minor (and keep -SNAPSHOT)
|
||||
$ sed -i 's/[0-9]\+\.[0-9]\+\.[0-9]\+\(.*CURRENT_OPENCENSUS_PROTO_VERSION\)/'$MAJOR.$((MINOR+1)).0'\1/' \
|
||||
"${VERSION_FILES[@]}"
|
||||
$ ./gradlew build
|
||||
$ git commit -a -m "Start $MAJOR.$((MINOR+1)).0 development cycle"
|
||||
```
|
||||
|
||||
- Go through PR review and push the master branch to GitHub:
|
||||
|
||||
```bash
|
||||
$ git checkout master
|
||||
$ git merge --ff-only bump-version
|
||||
$ git push upstream master
|
||||
```
|
||||
|
||||
4. For `vMajor.Minor.x` branch:
|
||||
|
||||
- Change root build files to remove "-SNAPSHOT" for the next release
|
||||
version (e.g. `0.4.0`). Commit the result and make a tag:
|
||||
|
||||
```bash
|
||||
$ git checkout -b release v$MAJOR.$MINOR.x
|
||||
# Change version to remove -SNAPSHOT
|
||||
$ sed -i 's/-SNAPSHOT\(.*CURRENT_OPENCENSUS_PROTO_VERSION\)/\1/' "${VERSION_FILES[@]}"
|
||||
$ ./gradlew build
|
||||
$ git commit -a -m "Bump version to $MAJOR.$MINOR.$PATCH"
|
||||
$ git tag -a v$MAJOR.$MINOR.$PATCH -m "Version $MAJOR.$MINOR.$PATCH"
|
||||
```
|
||||
|
||||
- Change root build files to the next snapshot version (e.g.
|
||||
`0.4.1-SNAPSHOT`). Commit the result:
|
||||
|
||||
```bash
|
||||
# Change version to next patch and add -SNAPSHOT
|
||||
$ sed -i 's/[0-9]\+\.[0-9]\+\.[0-9]\+\(.*CURRENT_OPENCENSUS_PROTO_VERSION\)/'$MAJOR.$MINOR.$((PATCH+1))-SNAPSHOT'\1/' \
|
||||
"${VERSION_FILES[@]}"
|
||||
$ ./gradlew build
|
||||
$ git commit -a -m "Bump version to $MAJOR.$MINOR.$((PATCH+1))-SNAPSHOT"
|
||||
```
|
||||
|
||||
- Go through PR review and push the release tag and updated release branch
|
||||
to GitHub:
|
||||
|
||||
```bash
|
||||
$ git checkout v$MAJOR.$MINOR.x
|
||||
$ git merge --ff-only release
|
||||
$ git push upstream v$MAJOR.$MINOR.$PATCH
|
||||
$ git push upstream v$MAJOR.$MINOR.x
|
||||
```
|
||||
|
||||
## Release Java Jar
|
||||
|
||||
Deployment to Maven Central (or the snapshot repo) is for all of the artifacts
|
||||
from the project.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you haven't done already, please follow the instructions
|
||||
[here](https://github.com/census-instrumentation/opencensus-java/blob/master/RELEASING.md#prerequisites)
|
||||
to set up the OSSRH (OSS Repository Hosting) account and signing keys. This is required for releasing
|
||||
to Maven Central.
|
||||
|
||||
### Branch
|
||||
|
||||
Before building/deploying, be sure to switch to the appropriate tag. The tag
|
||||
must reference a commit that has been pushed to the main repository, i.e., has
|
||||
gone through code review. For the current release use:
|
||||
|
||||
```bash
|
||||
$ git checkout -b v$MAJOR.$MINOR.$PATCH tags/v$MAJOR.$MINOR.$PATCH
|
||||
```
|
||||
|
||||
### Initial Deployment
|
||||
|
||||
The following command will build the whole project and upload it to Maven
|
||||
Central. Parallel building [is not safe during
|
||||
uploadArchives](https://issues.gradle.org/browse/GRADLE-3420).
|
||||
|
||||
```bash
|
||||
$ ./gradlew clean build && ./gradlew -Dorg.gradle.parallel=false uploadArchives
|
||||
```
|
||||
|
||||
If the version has the `-SNAPSHOT` suffix, the artifacts will automatically go
|
||||
to the snapshot repository. Otherwise it's a release deployment and the
|
||||
artifacts will go to a staging repository.
|
||||
|
||||
When deploying a Release, the deployment will create [a new staging
|
||||
repository](https://oss.sonatype.org/#stagingRepositories). You'll need to look
|
||||
up the ID in the OSSRH UI (usually in the form of `opencensus-*`).
|
||||
|
||||
### Releasing on Maven Central
|
||||
|
||||
Once all of the artifacts have been pushed to the staging repository, the
|
||||
repository must first be `closed`, which will trigger several sanity checks on
|
||||
the repository. If this completes successfully, the repository can then be
|
||||
`released`, which will begin the process of pushing the new artifacts to Maven
|
||||
Central (the staging repository will be destroyed in the process). You can see
|
||||
the complete process for releasing to Maven Central on the [OSSRH
|
||||
site](http://central.sonatype.org/pages/releasing-the-deployment.html).
|
||||
|
||||
## Announcement
|
||||
|
||||
Once deployment is done, go to Github [release
|
||||
page](https://github.com/census-instrumentation/opencensus-proto/releases), press
|
||||
`Draft a new release` to write release notes about the new release.
|
||||
|
||||
You can use `git log upstream/v$MAJOR.$((MINOR-1)).x..upstream/v$MAJOR.$MINOR.x --graph --first-parent`
|
||||
or the Github [compare tool](https://github.com/census-instrumentation/opencensus-proto/compare/)
|
||||
to view a summary of all commits since last release as a reference.
|
||||
|
||||
Please pick major or important user-visible changes only.
|
||||
170
vendor/github.com/census-instrumentation/opencensus-proto/build.gradle
generated
vendored
170
vendor/github.com/census-instrumentation/opencensus-proto/build.gradle
generated
vendored
|
|
@ -1,170 +0,0 @@
|
|||
description = 'Opencensus Proto'
|
||||
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'com.google.protobuf'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: "signing"
|
||||
|
||||
group = "io.opencensus"
|
||||
version = "0.1.0" // CURRENT_OPENCENSUS_PROTO_VERSION
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
repositories {
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
|
||||
jar.manifest {
|
||||
attributes('Implementation-Title': name,
|
||||
'Implementation-Version': version,
|
||||
'Built-By': System.getProperty('user.name'),
|
||||
'Built-JDK': System.getProperty('java.version'),
|
||||
'Source-Compatibility': sourceCompatibility,
|
||||
'Target-Compatibility': targetCompatibility)
|
||||
}
|
||||
|
||||
def protobufVersion = '3.5.1'
|
||||
def protocVersion = '3.5.1'
|
||||
def grpcVersion = "1.14.0" // CURRENT_GRPC_VERSION
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.6"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
proto {
|
||||
srcDir 'src'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "com.google.protobuf:protobuf-java:${protobufVersion}",
|
||||
"io.grpc:grpc-protobuf:${grpcVersion}",
|
||||
"io.grpc:grpc-stub:${grpcVersion}"
|
||||
|
||||
compileOnly "javax.annotation:javax.annotation-api:1.2"
|
||||
}
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
// The artifact spec for the Protobuf Compiler
|
||||
artifact = "com.google.protobuf:protoc:${protocVersion}"
|
||||
}
|
||||
plugins {
|
||||
grpc {
|
||||
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
|
||||
}
|
||||
}
|
||||
generateProtoTasks {
|
||||
all()*.plugins {
|
||||
grpc {}
|
||||
}
|
||||
ofSourceSet('main')
|
||||
}
|
||||
|
||||
generatedFilesBaseDir = "$projectDir/gen_gradle/src"
|
||||
}
|
||||
|
||||
// Disable all java warnings for proto generated files build
|
||||
compileJava {
|
||||
options.compilerArgs += ["-Xlint:none"]
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
clean {
|
||||
delete protobuf.generatedFilesBaseDir
|
||||
}
|
||||
|
||||
// IntelliJ complains that the generated classes are not found, ask IntelliJ to include the
|
||||
// generated Java directories as source folders.
|
||||
idea {
|
||||
module {
|
||||
sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java");
|
||||
// If you have additional sourceSets and/or codegen plugins, add all of them
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required false
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
javadoc.source = "$projectDir/gen_gradle/src"
|
||||
|
||||
javadoc.options {
|
||||
encoding = 'UTF-8'
|
||||
links 'https://docs.oracle.com/javase/8/docs/api/'
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives javadocJar, sourcesJar
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
def configureAuth = {
|
||||
if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) {
|
||||
authentication(userName:rootProject.ossrhUsername, password: rootProject.ossrhPassword)
|
||||
}
|
||||
}
|
||||
|
||||
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/", configureAuth)
|
||||
|
||||
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/", configureAuth)
|
||||
|
||||
pom.project {
|
||||
name "OpenCensus"
|
||||
packaging 'jar'
|
||||
description project.description
|
||||
url 'https://github.com/census-instrumentation/opencensus-proto'
|
||||
|
||||
scm {
|
||||
connection 'scm:svn:https://github.com/census-instrumentation/opencensus-proto'
|
||||
developerConnection 'scm:git:git@github.com/census-instrumentation/opencensus-proto'
|
||||
url 'https://github.com/census-instrumentation/opencensus-proto'
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'The Apache License, Version 2.0'
|
||||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'io.opencensus'
|
||||
name 'OpenCensus Contributors'
|
||||
email 'census-developers@googlegroups.com'
|
||||
url 'opencensus.io'
|
||||
// https://issues.gradle.org/browse/GRADLE-2719
|
||||
organization = 'OpenCensus Authors'
|
||||
organizationUrl 'https://www.opencensus.io'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
vendor/github.com/census-instrumentation/opencensus-proto/gradlew
generated
vendored
172
vendor/github.com/census-instrumentation/opencensus-proto/gradlew
generated
vendored
|
|
@ -1,172 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
vendor/github.com/census-instrumentation/opencensus-proto/gradlew.bat
generated
vendored
84
vendor/github.com/census-instrumentation/opencensus-proto/gradlew.bat
generated
vendored
|
|
@ -1,84 +0,0 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
vendor/github.com/census-instrumentation/opencensus-proto/settings.gradle
generated
vendored
1
vendor/github.com/census-instrumentation/opencensus-proto/settings.gradle
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
rootProject.name = "opencensus-proto"
|
||||
215
vendor/github.com/denisenkom/go-mssqldb/README.md
generated
vendored
215
vendor/github.com/denisenkom/go-mssqldb/README.md
generated
vendored
|
|
@ -1,215 +0,0 @@
|
|||
# A pure Go MSSQL driver for Go's database/sql package
|
||||
|
||||
[](http://godoc.org/github.com/denisenkom/go-mssqldb)
|
||||
[](https://ci.appveyor.com/project/denisenkom/go-mssqldb)
|
||||
[](https://codecov.io/gh/denisenkom/go-mssqldb)
|
||||
|
||||
## Install
|
||||
|
||||
Requires Go 1.8 or above.
|
||||
|
||||
Install with `go get github.com/denisenkom/go-mssqldb` .
|
||||
|
||||
## Connection Parameters and DSN
|
||||
|
||||
The recommended connection string uses a URL format:
|
||||
`sqlserver://username:password@host/instance?param1=value¶m2=value`
|
||||
Other supported formats are listed below.
|
||||
|
||||
### Common parameters:
|
||||
|
||||
* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used.
|
||||
* `password`
|
||||
* `database`
|
||||
* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts.
|
||||
* `dial timeout` - in seconds (default is 15), set to 0 for no timeout
|
||||
* `encrypt`
|
||||
* `disable` - Data send between client and server is not encrypted.
|
||||
* `false` - Data sent between client and server is not encrypted beyond the login packet. (Default)
|
||||
* `true` - Data sent between client and server is encrypted.
|
||||
* `app name` - The application name (default is go-mssqldb)
|
||||
|
||||
### Connection parameters for ODBC and ADO style connection strings:
|
||||
|
||||
* `server` - host or host\instance (default localhost)
|
||||
* `port` - used only when there is no instance in server (default 1433)
|
||||
|
||||
### Less common parameters:
|
||||
|
||||
* `keepAlive` - in seconds; 0 to disable (default is 30)
|
||||
* `failoverpartner` - host or host\instance (default is no partner).
|
||||
* `failoverport` - used only when there is no instance in failoverpartner (default 1433)
|
||||
* `packet size` - in bytes; 512 to 32767 (default is 4096)
|
||||
* Encrypted connections have a maximum packet size of 16383 bytes
|
||||
* Further information on usage: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option
|
||||
* `log` - logging flags (default 0/no logging, 63 for full logging)
|
||||
* 1 log errors
|
||||
* 2 log messages
|
||||
* 4 log rows affected
|
||||
* 8 trace sql statements
|
||||
* 16 log statement parameters
|
||||
* 32 log transaction begin/end
|
||||
* `TrustServerCertificate`
|
||||
* false - Server certificate is checked. Default is false if encypt is specified.
|
||||
* true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing.
|
||||
* `certificate` - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates.
|
||||
* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host.
|
||||
* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port.
|
||||
* `Workstation ID` - The workstation name (default is the host name)
|
||||
* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener.
|
||||
|
||||
### The connection string can be specified in one of three formats:
|
||||
|
||||
|
||||
1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as
|
||||
the first segment in the path. All other options are query parameters. Examples:
|
||||
|
||||
* `sqlserver://username:password@host/instance?param1=value¶m2=value`
|
||||
* `sqlserver://username:password@host:port?param1=value¶m2=value`
|
||||
* `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance.
|
||||
* `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass.
|
||||
* `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30` // port 1234 on localhost.
|
||||
* `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass"
|
||||
|
||||
A string of this format can be constructed using the `URL` type in the `net/url` package.
|
||||
|
||||
```go
|
||||
query := url.Values{}
|
||||
query.Add("app name", "MyAppName")
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: "sqlserver",
|
||||
User: url.UserPassword(username, password),
|
||||
Host: fmt.Sprintf("%s:%d", hostname, port),
|
||||
// Path: instance, // if connecting to an instance instead of a port
|
||||
RawQuery: query.Encode(),
|
||||
}
|
||||
db, err := sql.Open("sqlserver", u.String())
|
||||
```
|
||||
|
||||
2. ADO: `key=value` pairs separated by `;`. Values may not contain `;`, leading and trailing whitespace is ignored.
|
||||
Examples:
|
||||
|
||||
* `server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName`
|
||||
* `server=localhost;user id=sa;database=master;app name=MyAppName`
|
||||
|
||||
3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping
|
||||
values in `{}`. Examples:
|
||||
|
||||
* `odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName`
|
||||
* `odbc:server=localhost;user id=sa;database=master;app name=MyAppName`
|
||||
* `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar "
|
||||
* `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar"
|
||||
|
||||
## Executing Stored Procedures
|
||||
|
||||
To run a stored procedure, set the query text to the procedure name:
|
||||
```go
|
||||
var account = "abc"
|
||||
_, err := db.ExecContext(ctx, "sp_RunMe",
|
||||
sql.Named("ID", 123),
|
||||
sql.Named("Account", sql.Out{Dest: &account}),
|
||||
)
|
||||
```
|
||||
|
||||
## Return Status
|
||||
|
||||
To get the procedure return status, pass into the parameters a
|
||||
`*mssql.ReturnStatus`. For example:
|
||||
```
|
||||
var rs mssql.ReturnStatus
|
||||
_, err := db.ExecContext(ctx, "theproc", &rs)
|
||||
log.Printf("status=%d", rs)
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in
|
||||
the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position).
|
||||
|
||||
```go
|
||||
db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob")
|
||||
```
|
||||
|
||||
### Parameter Types
|
||||
|
||||
To pass specific types to the query parameters, say `varchar` or `date` types,
|
||||
you must convert the types to the type before passing in. The following types
|
||||
are supported:
|
||||
|
||||
* string -> nvarchar
|
||||
* mssql.VarChar -> varchar
|
||||
* time.Time -> datetimeoffset or datetime (TDS version dependent)
|
||||
* mssql.DateTime1 -> datetime
|
||||
* mssql.DateTimeOffset -> datetimeoffset
|
||||
* "cloud.google.com/go/civil".Date -> date
|
||||
* "cloud.google.com/go/civil".DateTime -> datetime2
|
||||
* "cloud.google.com/go/civil".Time -> time
|
||||
|
||||
## Important Notes
|
||||
|
||||
* [LastInsertId](https://golang.org/pkg/database/sql/#Result.LastInsertId) should
|
||||
not be used with this driver (or SQL Server) due to how the TDS protocol
|
||||
works. Please use the [OUTPUT Clause](https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql)
|
||||
or add a `select ID = convert(bigint, SCOPE_IDENTITY());` to the end of your
|
||||
query (ref [SCOPE_IDENTITY](https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql)).
|
||||
This will ensure you are getting the correct ID and will prevent a network round trip.
|
||||
* [NewConnector](https://godoc.org/github.com/denisenkom/go-mssqldb#NewConnector)
|
||||
may be used with [OpenDB](https://golang.org/pkg/database/sql/#OpenDB).
|
||||
* [Connector.SessionInitSQL](https://godoc.org/github.com/denisenkom/go-mssqldb#Connector.SessionInitSQL)
|
||||
may be set to set any driver specific session settings after the session
|
||||
has been reset. If empty the session will still be reset but use the database
|
||||
defaults in Go1.10+.
|
||||
|
||||
## Features
|
||||
|
||||
* Can be used with SQL Server 2005 or newer
|
||||
* Can be used with Microsoft Azure SQL Database
|
||||
* Can be used on all go supported platforms (e.g. Linux, Mac OS X and Windows)
|
||||
* Supports new date/time types: date, time, datetime2, datetimeoffset
|
||||
* Supports string parameters longer than 8000 characters
|
||||
* Supports encryption using SSL/TLS
|
||||
* Supports SQL Server and Windows Authentication
|
||||
* Supports Single-Sign-On on Windows
|
||||
* Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas.
|
||||
* Supports query notifications
|
||||
|
||||
## Tests
|
||||
|
||||
`go test` is used for testing. A running instance of MSSQL server is required.
|
||||
Environment variables are used to pass login information.
|
||||
|
||||
Example:
|
||||
|
||||
env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test
|
||||
|
||||
## Deprecated
|
||||
|
||||
These features still exist in the driver, but they are are deprecated.
|
||||
|
||||
### Query Parameter Token Replace (driver "mssql")
|
||||
|
||||
If you use the driver name "mssql" (rather then "sqlserver") the SQL text
|
||||
will be loosly parsed and an attempt to extract identifiers using one of
|
||||
|
||||
* ?
|
||||
* ?nnn
|
||||
* :nnn
|
||||
* $nnn
|
||||
|
||||
will be used. This is not recommended with SQL Server.
|
||||
There is at least one existing `won't fix` issue with the query parsing.
|
||||
|
||||
Use the native "@Name" parameters instead with the "sqlserver" driver name.
|
||||
|
||||
## Known Issues
|
||||
|
||||
* SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled.
|
||||
To fix SQL Server 2008 R2 issue, install SQL Server 2008 R2 Service Pack 2.
|
||||
To fix SQL Server 2008 issue, install Microsoft SQL Server 2008 Service Pack 3 and Cumulative update package 3 for SQL Server 2008 SP3.
|
||||
More information: http://support.microsoft.com/kb/2653857
|
||||
48
vendor/github.com/denisenkom/go-mssqldb/appveyor.yml
generated
vendored
48
vendor/github.com/denisenkom/go-mssqldb/appveyor.yml
generated
vendored
|
|
@ -1,48 +0,0 @@
|
|||
version: 1.0.{build}
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\denisenkom\go-mssqldb
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
HOST: localhost
|
||||
SQLUSER: sa
|
||||
SQLPASSWORD: Password12!
|
||||
DATABASE: test
|
||||
GOVERSION: 110
|
||||
matrix:
|
||||
- GOVERSION: 18
|
||||
SQLINSTANCE: SQL2016
|
||||
- GOVERSION: 19
|
||||
SQLINSTANCE: SQL2016
|
||||
- GOVERSION: 110
|
||||
SQLINSTANCE: SQL2016
|
||||
- SQLINSTANCE: SQL2014
|
||||
- SQLINSTANCE: SQL2012SP1
|
||||
- SQLINSTANCE: SQL2008R2SP2
|
||||
|
||||
install:
|
||||
- set GOROOT=c:\go%GOVERSION%
|
||||
- set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH%
|
||||
- go version
|
||||
- go env
|
||||
- go get -u cloud.google.com/go/civil
|
||||
|
||||
build_script:
|
||||
- go build
|
||||
|
||||
before_test:
|
||||
# setup SQL Server
|
||||
- ps: |
|
||||
$instanceName = $env:SQLINSTANCE
|
||||
Start-Service "MSSQL`$$instanceName"
|
||||
Start-Service "SQLBrowser"
|
||||
- sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;"
|
||||
- sqlcmd -S "(local)\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version"
|
||||
- pip install codecov
|
||||
|
||||
|
||||
test_script:
|
||||
- go test -race -cpu 4 -coverprofile=coverage.txt -covermode=atomic
|
||||
- codecov -f coverage.txt
|
||||
284
vendor/github.com/denisenkom/go-mssqldb/buf_test.go
generated
vendored
284
vendor/github.com/denisenkom/go-mssqldb/buf_test.go
generated
vendored
|
|
@ -1,284 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type closableBuffer struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
func (closableBuffer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type failBuffer struct {
|
||||
}
|
||||
|
||||
func (failBuffer) Read([]byte) (int, error) {
|
||||
return 0, errors.New("read failed")
|
||||
}
|
||||
|
||||
func (failBuffer) Write([]byte) (int, error) {
|
||||
return 0, errors.New("write failed")
|
||||
}
|
||||
|
||||
func (failBuffer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeBuf(bufSize uint16, testData []byte) *tdsBuffer {
|
||||
buffer := closableBuffer{bytes.NewBuffer(testData)}
|
||||
return newTdsBuffer(bufSize, &buffer)
|
||||
}
|
||||
|
||||
func TestStreamShorterThanHeader(t *testing.T) {
|
||||
//buffer := closableBuffer{*bytes.NewBuffer([]byte{0xFF, 0xFF})}
|
||||
//buffer := closableBuffer{*bytes.NewBuffer([]byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF})}
|
||||
//tdsBuffer := newTdsBuffer(100, &buffer)
|
||||
buffer := makeBuf(100, []byte{0xFF, 0xFF})
|
||||
_, err := buffer.BeginRead()
|
||||
if err == nil {
|
||||
t.Fatal("BeginRead was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("BeginRead failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidLengthInHeaderTooLong(t *testing.T) {
|
||||
buffer := makeBuf(8, []byte{0xFF, 0xFF, 0x0, 0x9, 0xff, 0xff, 0xff, 0xff})
|
||||
_, err := buffer.BeginRead()
|
||||
if err == nil {
|
||||
t.Fatal("BeginRead was expected to return error but it didn't")
|
||||
} else {
|
||||
if err.Error() != "Invalid packet size, it is longer than buffer size" {
|
||||
t.Fatal("BeginRead failed with incorrect error", err)
|
||||
} else {
|
||||
t.Log("BeginRead failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidLengthInHeaderTooShort(t *testing.T) {
|
||||
buffer := makeBuf(100, []byte{0xFF, 0xFF, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff})
|
||||
_, err := buffer.BeginRead()
|
||||
if err == nil {
|
||||
t.Fatal("BeginRead was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("BeginRead failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidLengthInHeaderLongerThanIncomingBuffer(t *testing.T) {
|
||||
buffer := makeBuf(9, []byte{0xFF, 0xFF, 0x0, 0x9, 0xff, 0xff, 0xff, 0xff})
|
||||
_, err := buffer.BeginRead()
|
||||
if err == nil {
|
||||
t.Fatal("BeginRead was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("BeginRead failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeginReadSucceeds(t *testing.T) {
|
||||
buffer := makeBuf(9, []byte{0x01 /*id*/, 0xFF /*status*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02 /*test byte*/})
|
||||
|
||||
id, err := buffer.BeginRead()
|
||||
if err != nil {
|
||||
t.Fatal("BeginRead failed:", err.Error())
|
||||
}
|
||||
if id != 1 {
|
||||
t.Fatalf("Expected id to be 1 but it is %d", id)
|
||||
}
|
||||
|
||||
b, err := buffer.ReadByte()
|
||||
if err != nil {
|
||||
t.Fatal("ReadByte failed:", err.Error())
|
||||
}
|
||||
if b != 2 {
|
||||
t.Fatalf("Expected read byte to be 2 but it is %d", b)
|
||||
}
|
||||
|
||||
// should fail because no more bytes left
|
||||
_, err = buffer.ReadByte()
|
||||
if err == nil {
|
||||
t.Fatal("ReadByte was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("ReadByte failed as expected with error:", err.Error())
|
||||
}
|
||||
|
||||
testBuf := []byte{0, 1, 2}
|
||||
// should fail because no more bytes left
|
||||
_, err = buffer.Read(testBuf)
|
||||
if err == nil {
|
||||
t.Fatal("Read was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("Read failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadByteFailsOnSecondPacket(t *testing.T) {
|
||||
buffer := makeBuf(9, []byte{
|
||||
0x01 /*id*/, 0x0 /*not final*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02, /*test byte*/
|
||||
0x01 /*next id, this packet is invalid, it is too short*/})
|
||||
|
||||
_, err := buffer.BeginRead()
|
||||
if err != nil {
|
||||
t.Fatal("BeginRead failed:", err.Error())
|
||||
}
|
||||
|
||||
_, err = buffer.ReadByte()
|
||||
if err != nil {
|
||||
t.Fatal("ReadByte failed:", err.Error())
|
||||
}
|
||||
|
||||
_, err = buffer.ReadByte()
|
||||
if err == nil {
|
||||
t.Fatal("ReadByte was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("ReadByte failed as expected with error:", err.Error())
|
||||
}
|
||||
|
||||
t.Run("test byte() panic", func(t *testing.T) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
buffer.byte()
|
||||
t.Fatal("byte() should panic, but it didn't")
|
||||
})
|
||||
|
||||
t.Run("test ReadFull() panic", func(t *testing.T) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
buf := make([]byte, 10)
|
||||
buffer.ReadFull(buf)
|
||||
t.Fatal("ReadFull() should panic, but it didn't")
|
||||
})
|
||||
}
|
||||
|
||||
func TestReadFailsOnSecondPacket(t *testing.T) {
|
||||
buffer := makeBuf(9, []byte{
|
||||
0x01 /*id*/, 0x0 /*not final*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02, /*test byte*/
|
||||
0x01 /*next id, this packet is invalid, it is too short*/})
|
||||
|
||||
_, err := buffer.BeginRead()
|
||||
if err != nil {
|
||||
t.Fatal("BeginRead failed:", err.Error())
|
||||
}
|
||||
|
||||
testBuf := []byte{0}
|
||||
_, err = buffer.Read(testBuf)
|
||||
if err != nil {
|
||||
t.Fatal("Read failed:", err.Error())
|
||||
}
|
||||
if testBuf[0] != 2 {
|
||||
t.Fatal("Read returned invalid value")
|
||||
}
|
||||
|
||||
_, err = buffer.Read(testBuf)
|
||||
if err == nil {
|
||||
t.Fatal("ReadByte was expected to return error but it didn't")
|
||||
} else {
|
||||
t.Log("ReadByte failed as expected with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
memBuf := bytes.NewBuffer([]byte{})
|
||||
buf := newTdsBuffer(11, closableBuffer{memBuf})
|
||||
buf.BeginPacket(1, false)
|
||||
err := buf.WriteByte(2)
|
||||
if err != nil {
|
||||
t.Fatal("WriteByte failed:", err.Error())
|
||||
}
|
||||
wrote, err := buf.Write([]byte{3, 4})
|
||||
if err != nil {
|
||||
t.Fatal("Write failed:", err.Error())
|
||||
}
|
||||
if wrote != 2 {
|
||||
t.Fatalf("Write returned invalid value of written bytes %d", wrote)
|
||||
}
|
||||
|
||||
err = buf.FinishPacket()
|
||||
if err != nil {
|
||||
t.Fatal("FinishPacket failed:", err.Error())
|
||||
}
|
||||
if bytes.Compare(memBuf.Bytes(), []byte{1, 1, 0, 11, 0, 0, 1, 0, 2, 3, 4}) != 0 {
|
||||
t.Fatalf("Written buffer has invalid content: %v", memBuf.Bytes())
|
||||
}
|
||||
|
||||
buf.BeginPacket(2, false)
|
||||
wrote, err = buf.Write([]byte{3, 4, 5, 6})
|
||||
if err != nil {
|
||||
t.Fatal("Write failed:", err.Error())
|
||||
}
|
||||
if wrote != 4 {
|
||||
t.Fatalf("Write returned invalid value of written bytes %d", wrote)
|
||||
}
|
||||
err = buf.FinishPacket()
|
||||
if err != nil {
|
||||
t.Fatal("FinishPacket failed:", err.Error())
|
||||
}
|
||||
expectedBuf := []byte{
|
||||
1, 1, 0, 11, 0, 0, 1, 0, 2, 3, 4, // packet 1
|
||||
2, 0, 0, 11, 0, 0, 1, 0, 3, 4, 5, // packet 2
|
||||
2, 1, 0, 9, 0, 0, 2, 0, 6, // packet 3
|
||||
}
|
||||
if bytes.Compare(memBuf.Bytes(), expectedBuf) != 0 {
|
||||
t.Fatalf("Written buffer has invalid content:\n got: %v\nwant: %v", memBuf.Bytes(), expectedBuf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteErrors(t *testing.T) {
|
||||
// write should fail if underlying transport fails
|
||||
buf := newTdsBuffer(uint16(headerSize)+1, failBuffer{})
|
||||
buf.BeginPacket(1, false)
|
||||
wrote, err := buf.Write([]byte{0, 0})
|
||||
// may change from error to panic in future
|
||||
if err == nil {
|
||||
t.Fatal("Write should fail but it didn't")
|
||||
}
|
||||
if wrote != 1 {
|
||||
t.Fatal("Should write 1 byte but it wrote ", wrote)
|
||||
}
|
||||
|
||||
// writebyte should fail if underlying transport fails
|
||||
buf = newTdsBuffer(uint16(headerSize)+1, failBuffer{})
|
||||
buf.BeginPacket(1, false)
|
||||
// first write should not fail because if fits in the buffer
|
||||
err = buf.WriteByte(0)
|
||||
if err != nil {
|
||||
t.Fatal("First WriteByte should not fail because it should fit in the buffer, but it failed", err)
|
||||
}
|
||||
err = buf.WriteByte(0)
|
||||
// may change from error to panic in future
|
||||
if err == nil {
|
||||
t.Fatal("Second WriteByte should fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite_BufferBounds(t *testing.T) {
|
||||
memBuf := bytes.NewBuffer([]byte{})
|
||||
buf := newTdsBuffer(11, closableBuffer{memBuf})
|
||||
|
||||
buf.BeginPacket(1, false)
|
||||
// write bytes enough to complete a package
|
||||
_, err := buf.Write([]byte{1, 1, 1})
|
||||
if err != nil {
|
||||
t.Fatal("Write failed:", err.Error())
|
||||
}
|
||||
err = buf.WriteByte(1)
|
||||
if err != nil {
|
||||
t.Fatal("WriteByte failed:", err.Error())
|
||||
}
|
||||
_, err = buf.Write([]byte{1, 1, 1})
|
||||
if err != nil {
|
||||
t.Fatal("Write failed:", err.Error())
|
||||
}
|
||||
err = buf.FinishPacket()
|
||||
if err != nil {
|
||||
t.Fatal("FinishPacket failed:", err.Error())
|
||||
}
|
||||
}
|
||||
237
vendor/github.com/denisenkom/go-mssqldb/bulkcopy_test.go
generated
vendored
237
vendor/github.com/denisenkom/go-mssqldb/bulkcopy_test.go
generated
vendored
|
|
@ -1,237 +0,0 @@
|
|||
// +build go1.9
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBulkcopy(t *testing.T) {
|
||||
// TDS level Bulk Insert is not supported on Azure SQL Server.
|
||||
if dsn := makeConnStr(t); strings.HasSuffix(strings.Split(dsn.Host, ":")[0], ".database.windows.net") {
|
||||
t.Skip("TDS level bulk copy is not supported on Azure SQL Server")
|
||||
}
|
||||
type testValue struct {
|
||||
colname string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
tableName := "#table_test"
|
||||
geom, _ := hex.DecodeString("E6100000010C00000000000034400000000000004440")
|
||||
bin, _ := hex.DecodeString("ba8b7782168d4033a299333aec17bd33")
|
||||
testValues := []testValue{
|
||||
|
||||
{"test_nvarchar", "ab©ĎéⒻghïjklmnopqЯ☀tuvwxyz"},
|
||||
{"test_varchar", "abcdefg"},
|
||||
{"test_char", "abcdefg "},
|
||||
{"test_nchar", "abcdefg "},
|
||||
{"test_text", "abcdefg"},
|
||||
{"test_ntext", "abcdefg"},
|
||||
{"test_float", 1234.56},
|
||||
{"test_floatn", 1234.56},
|
||||
{"test_real", 1234.56},
|
||||
{"test_realn", 1234.56},
|
||||
{"test_bit", true},
|
||||
{"test_bitn", nil},
|
||||
{"test_smalldatetime", time.Date(2010, 11, 12, 13, 14, 0, 0, time.UTC)},
|
||||
{"test_smalldatetimen", time.Date(2010, 11, 12, 13, 14, 0, 0, time.UTC)},
|
||||
{"test_datetime", time.Date(2010, 11, 12, 13, 14, 15, 120000000, time.UTC)},
|
||||
{"test_datetimen", time.Date(2010, 11, 12, 13, 14, 15, 120000000, time.UTC)},
|
||||
{"test_datetimen_1", time.Date(4010, 11, 12, 13, 14, 15, 120000000, time.UTC)},
|
||||
{"test_datetime2_1", time.Date(2010, 11, 12, 13, 14, 15, 0, time.UTC)},
|
||||
{"test_datetime2_3", time.Date(2010, 11, 12, 13, 14, 15, 123000000, time.UTC)},
|
||||
{"test_datetime2_7", time.Date(2010, 11, 12, 13, 14, 15, 123000000, time.UTC)},
|
||||
{"test_date", time.Date(2010, 11, 12, 00, 00, 00, 0, time.UTC)},
|
||||
{"test_tinyint", 255},
|
||||
{"test_smallint", 32767},
|
||||
{"test_smallintn", nil},
|
||||
{"test_int", 2147483647},
|
||||
{"test_bigint", 9223372036854775807},
|
||||
{"test_bigintn", nil},
|
||||
{"test_geom", geom},
|
||||
{"test_uniqueidentifier", []byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}},
|
||||
// {"test_smallmoney", 1234.56},
|
||||
// {"test_money", 1234.56},
|
||||
{"test_decimal_18_0", 1234.0001},
|
||||
{"test_decimal_9_2", 1234.560001},
|
||||
{"test_decimal_20_0", 1234.0001},
|
||||
{"test_numeric_30_10", 1234567.1234567},
|
||||
{"test_varbinary", []byte("1")},
|
||||
{"test_varbinary_16", bin},
|
||||
{"test_varbinary_max", bin},
|
||||
{"test_binary", []byte("1")},
|
||||
{"test_binary_16", bin},
|
||||
}
|
||||
|
||||
columns := make([]string, len(testValues))
|
||||
for i, val := range testValues {
|
||||
columns[i] = val.colname
|
||||
}
|
||||
|
||||
values := make([]interface{}, len(testValues))
|
||||
for i, val := range testValues {
|
||||
values[i] = val.val
|
||||
}
|
||||
|
||||
pool := open(t)
|
||||
defer pool.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Now that session resetting is supported, the use of the per session
|
||||
// temp table requires the use of a dedicated connection from the connection
|
||||
// pool.
|
||||
conn, err := pool.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal("failed to pull connection from pool", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
err = setupTable(ctx, t, conn, tableName)
|
||||
if err != nil {
|
||||
t.Error("Setup table failed: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Log("Preparing copy in statement")
|
||||
|
||||
stmt, err := conn.PrepareContext(ctx, CopyIn(tableName, BulkOptions{}, columns...))
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
t.Logf("Executing copy in statement %d time with %d values", i+1, len(values))
|
||||
_, err = stmt.Exec(values...)
|
||||
if err != nil {
|
||||
t.Error("AddRow failed: ", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result, err := stmt.Exec()
|
||||
if err != nil {
|
||||
t.Fatal("bulkcopy failed: ", err.Error())
|
||||
}
|
||||
|
||||
insertedRowCount, _ := result.RowsAffected()
|
||||
if insertedRowCount == 0 {
|
||||
t.Fatal("0 row inserted!")
|
||||
}
|
||||
|
||||
//check that all rows are present
|
||||
var rowCount int
|
||||
err = conn.QueryRowContext(ctx, "select count(*) c from "+tableName).Scan(&rowCount)
|
||||
|
||||
if rowCount != 10 {
|
||||
t.Errorf("unexpected row count %d", rowCount)
|
||||
}
|
||||
|
||||
//data verification
|
||||
rows, err := conn.QueryContext(ctx, "select "+strings.Join(columns, ",")+" from "+tableName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
|
||||
ptrs := make([]interface{}, len(columns))
|
||||
container := make([]interface{}, len(columns))
|
||||
for i, _ := range ptrs {
|
||||
ptrs[i] = &container[i]
|
||||
}
|
||||
if err := rows.Scan(ptrs...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, c := range testValues {
|
||||
if !compareValue(container[i], c.val) {
|
||||
t.Errorf("columns %s : expected: %v, got: %v\n", c.colname, c.val, container[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func compareValue(a interface{}, expected interface{}) bool {
|
||||
switch expected := expected.(type) {
|
||||
case int:
|
||||
return int64(expected) == a
|
||||
case int32:
|
||||
return int64(expected) == a
|
||||
case int64:
|
||||
return int64(expected) == a
|
||||
case float64:
|
||||
if got, ok := a.([]uint8); ok {
|
||||
var nf sql.NullFloat64
|
||||
nf.Scan(got)
|
||||
a = nf.Float64
|
||||
}
|
||||
return math.Abs(expected-a.(float64)) < 0.0001
|
||||
default:
|
||||
return reflect.DeepEqual(expected, a)
|
||||
}
|
||||
}
|
||||
|
||||
func setupTable(ctx context.Context, t *testing.T, conn *sql.Conn, tableName string) (err error) {
|
||||
tablesql := `CREATE TABLE ` + tableName + ` (
|
||||
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||
[test_nvarchar] [nvarchar](50) NULL,
|
||||
[test_varchar] [varchar](50) NULL,
|
||||
[test_char] [char](10) NULL,
|
||||
[test_nchar] [nchar](10) NULL,
|
||||
[test_text] [text] NULL,
|
||||
[test_ntext] [ntext] NULL,
|
||||
[test_float] [float] NOT NULL,
|
||||
[test_floatn] [float] NULL,
|
||||
[test_real] [real] NULL,
|
||||
[test_realn] [real] NULL,
|
||||
[test_bit] [bit] NOT NULL,
|
||||
[test_bitn] [bit] NULL,
|
||||
[test_smalldatetime] [smalldatetime] NOT NULL,
|
||||
[test_smalldatetimen] [smalldatetime] NULL,
|
||||
[test_datetime] [datetime] NOT NULL,
|
||||
[test_datetimen] [datetime] NULL,
|
||||
[test_datetimen_1] [datetime] NULL,
|
||||
[test_datetime2_1] [datetime2](1) NULL,
|
||||
[test_datetime2_3] [datetime2](3) NULL,
|
||||
[test_datetime2_7] [datetime2](7) NULL,
|
||||
[test_date] [date] NULL,
|
||||
[test_smallmoney] [smallmoney] NULL,
|
||||
[test_money] [money] NULL,
|
||||
[test_tinyint] [tinyint] NULL,
|
||||
[test_smallint] [smallint] NOT NULL,
|
||||
[test_smallintn] [smallint] NULL,
|
||||
[test_int] [int] NULL,
|
||||
[test_bigint] [bigint] NOT NULL,
|
||||
[test_bigintn] [bigint] NULL,
|
||||
[test_geom] [geometry] NULL,
|
||||
[test_geog] [geography] NULL,
|
||||
[text_xml] [xml] NULL,
|
||||
[test_uniqueidentifier] [uniqueidentifier] NULL,
|
||||
[test_decimal_18_0] [decimal](18, 0) NULL,
|
||||
[test_decimal_9_2] [decimal](9, 2) NULL,
|
||||
[test_decimal_20_0] [decimal](20, 0) NULL,
|
||||
[test_numeric_30_10] [decimal](30, 10) NULL,
|
||||
[test_varbinary] VARBINARY NOT NULL,
|
||||
[test_varbinary_16] VARBINARY(16) NOT NULL,
|
||||
[test_varbinary_max] VARBINARY(max) NOT NULL,
|
||||
[test_binary] BINARY NOT NULL,
|
||||
[test_binary_16] BINARY(16) NOT NULL,
|
||||
CONSTRAINT [PK_` + tableName + `_id] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];`
|
||||
_, err = conn.ExecContext(ctx, tablesql)
|
||||
if err != nil {
|
||||
t.Fatal("tablesql failed:", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
107
vendor/github.com/denisenkom/go-mssqldb/decimal_test.go
generated
vendored
107
vendor/github.com/denisenkom/go-mssqldb/decimal_test.go
generated
vendored
|
|
@ -1,107 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToString(t *testing.T) {
|
||||
values := []struct {
|
||||
dec Decimal
|
||||
s string
|
||||
}{
|
||||
{Decimal{positive: true, prec: 10, scale: 0, integer: [4]uint32{1, 0, 0, 0}}, "1"},
|
||||
{Decimal{positive: false, prec: 10, scale: 0, integer: [4]uint32{1, 0, 0, 0}}, "-1"},
|
||||
{Decimal{positive: true, prec: 10, scale: 1, integer: [4]uint32{1, 0, 0, 0}}, "0.1"},
|
||||
{Decimal{positive: true, prec: 10, scale: 2, integer: [4]uint32{1, 0, 0, 0}}, "0.01"},
|
||||
{Decimal{positive: false, prec: 10, scale: 1, integer: [4]uint32{1, 0, 0, 0}}, "-0.1"},
|
||||
{Decimal{positive: true, prec: 10, scale: 2, integer: [4]uint32{100, 0, 0, 0}}, "1.00"},
|
||||
{Decimal{positive: false, prec: 10, scale: 2, integer: [4]uint32{100, 0, 0, 0}}, "-1.00"},
|
||||
{Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 1, 0, 0}}, "4294967296"}, // 2^32
|
||||
{Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 0, 1, 0}}, "18446744073709551616"}, // 2^64
|
||||
{Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 1, 1, 0}}, "18446744078004518912"}, // 2^64+2^32
|
||||
}
|
||||
for _, v := range values {
|
||||
if v.dec.String() != v.s {
|
||||
t.Error("String values don't match ", v.dec.String(), v.s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToFloat64(t *testing.T) {
|
||||
values := []struct {
|
||||
dec Decimal
|
||||
flt float64
|
||||
}{
|
||||
{Decimal{positive: true, prec: 1},
|
||||
0.0},
|
||||
{Decimal{positive: true, prec: 1, integer: [4]uint32{1}},
|
||||
1.0},
|
||||
{Decimal{positive: false, prec: 1, integer: [4]uint32{1}},
|
||||
-1.0},
|
||||
{Decimal{positive: true, prec: 1, scale: 1, integer: [4]uint32{5}},
|
||||
0.5},
|
||||
{Decimal{positive: true, prec: 38, integer: [4]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}},
|
||||
3.402823669209385e+38},
|
||||
{Decimal{positive: true, prec: 38, scale: 3, integer: [4]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}},
|
||||
3.402823669209385e+35},
|
||||
}
|
||||
for _, v := range values {
|
||||
if v.dec.ToFloat64() != v.flt {
|
||||
t.Error("ToFloat values don't match ", v.dec.ToFloat64(), v.flt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromFloat64(t *testing.T) {
|
||||
values := []struct {
|
||||
dec Decimal
|
||||
flt float64
|
||||
}{
|
||||
{Decimal{positive: true, prec: 20},
|
||||
0.0},
|
||||
{Decimal{positive: true, prec: 20, integer: [4]uint32{1}},
|
||||
1.0},
|
||||
{Decimal{positive: false, prec: 20, integer: [4]uint32{1}},
|
||||
-1.0},
|
||||
{Decimal{positive: true, prec: 20, scale: 1, integer: [4]uint32{5}},
|
||||
0.5},
|
||||
{Decimal{positive: true, prec: 20, integer: [4]uint32{0, 0, 0xfffff000, 0xffffffff}},
|
||||
3.402823669209384e+38},
|
||||
//{Decimal{positive: true, prec: 20, scale: 3, integer: [4]uint32{0, 0, 0xfffff000, 0xffffffff}},
|
||||
// 3.402823669209385e+35},
|
||||
}
|
||||
for _, v := range values {
|
||||
decfromflt, err := Float64ToDecimal(v.flt)
|
||||
if err == nil {
|
||||
if decfromflt != v.dec {
|
||||
t.Error("FromFloat values don't match ", decfromflt, v.dec)
|
||||
}
|
||||
} else {
|
||||
t.Error("Float64ToDecimal failed with error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
_, err := Float64ToDecimal(math.NaN())
|
||||
if err == nil {
|
||||
t.Error("Expected to get error for conversion from NaN, but didn't")
|
||||
}
|
||||
|
||||
_, err = Float64ToDecimal(math.Inf(1))
|
||||
if err == nil {
|
||||
t.Error("Expected to get error for conversion from positive infinity, but didn't")
|
||||
}
|
||||
|
||||
_, err = Float64ToDecimal(math.Inf(-1))
|
||||
if err == nil {
|
||||
t.Error("Expected to get error for conversion from negative infinity, but didn't")
|
||||
}
|
||||
_, err = Float64ToDecimal(3.402823669209386e+38)
|
||||
if err == nil {
|
||||
t.Error("Expected to get error for conversion from too big number, but didn't")
|
||||
}
|
||||
_, err = Float64ToDecimal(-3.402823669209386e+38)
|
||||
if err == nil {
|
||||
t.Error("Expected to get error for conversion from too big number, but didn't")
|
||||
}
|
||||
}
|
||||
38
vendor/github.com/denisenkom/go-mssqldb/error_example_test.go
generated
vendored
38
vendor/github.com/denisenkom/go-mssqldb/error_example_test.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleError_1() {
|
||||
// call a function that might return a mssql error
|
||||
err := callUsingMSSQL()
|
||||
|
||||
type ErrorWithNumber interface {
|
||||
SQLErrorNumber() int32
|
||||
}
|
||||
|
||||
if errorWithNumber, ok := err.(ErrorWithNumber); ok {
|
||||
if errorWithNumber.SQLErrorNumber() == 1205 {
|
||||
fmt.Println("deadlock error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleError_2() {
|
||||
// call a function that might return a mssql error
|
||||
err := callUsingMSSQL()
|
||||
|
||||
type SQLError interface {
|
||||
SQLErrorNumber() int32
|
||||
SQLErrorMessage() string
|
||||
}
|
||||
|
||||
if sqlError, ok := err.(SQLError); ok {
|
||||
if sqlError.SQLErrorNumber() == 1205 {
|
||||
fmt.Println("deadlock error", sqlError.SQLErrorMessage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func callUsingMSSQL() error {
|
||||
return nil
|
||||
}
|
||||
39
vendor/github.com/denisenkom/go-mssqldb/mssql_test.go
generated
vendored
39
vendor/github.com/denisenkom/go-mssqldb/mssql_test.go
generated
vendored
|
|
@ -1,39 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBadOpen(t *testing.T) {
|
||||
drv := driverWithProcess(t)
|
||||
_, err := drv.open(context.Background(), "port=bad")
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsProc(t *testing.T) {
|
||||
list := []struct {
|
||||
s string
|
||||
is bool
|
||||
}{
|
||||
{"proc", true},
|
||||
{"select 1;", false},
|
||||
{"select 1", false},
|
||||
{"[proc 1]", true},
|
||||
{"[proc\n1]", false},
|
||||
{"schema.name", true},
|
||||
{"[schema].[name]", true},
|
||||
{"schema.[name]", true},
|
||||
{"[schema].name", true},
|
||||
{"schema.[proc name]", true},
|
||||
}
|
||||
|
||||
for _, item := range list {
|
||||
got := isProc(item.s)
|
||||
if got != item.is {
|
||||
t.Errorf("for %q, got %t want %t", item.s, got, item.is)
|
||||
}
|
||||
}
|
||||
}
|
||||
76
vendor/github.com/denisenkom/go-mssqldb/ntlm_test.go
generated
vendored
76
vendor/github.com/denisenkom/go-mssqldb/ntlm_test.go
generated
vendored
|
|
@ -1,76 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLMOWFv1(t *testing.T) {
|
||||
hash := lmHash("Password")
|
||||
val := [21]byte{
|
||||
0xe5, 0x2c, 0xac, 0x67, 0x41, 0x9a, 0x9a, 0x22,
|
||||
0x4a, 0x3b, 0x10, 0x8f, 0x3f, 0xa6, 0xcb, 0x6d,
|
||||
0, 0, 0, 0, 0,
|
||||
}
|
||||
if hash != val {
|
||||
t.Errorf("got:\n%sexpected:\n%s", hex.Dump(hash[:]), hex.Dump(val[:]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNTLMOWFv1(t *testing.T) {
|
||||
hash := ntlmHash("Password")
|
||||
val := [21]byte{
|
||||
0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca, 0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52,
|
||||
0, 0, 0, 0, 0,
|
||||
}
|
||||
if hash != val {
|
||||
t.Errorf("got:\n%sexpected:\n%s", hex.Dump(hash[:]), hex.Dump(val[:]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNTLMv1Response(t *testing.T) {
|
||||
challenge := [8]byte{
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
}
|
||||
nt := ntResponse(challenge, "Password")
|
||||
val := [24]byte{
|
||||
0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6, 0x4f, 0x16, 0x33, 0x1c,
|
||||
0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94,
|
||||
}
|
||||
if nt != val {
|
||||
t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLMv1Response(t *testing.T) {
|
||||
challenge := [8]byte{
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
}
|
||||
nt := lmResponse(challenge, "Password")
|
||||
val := [24]byte{
|
||||
0x98, 0xde, 0xf7, 0xb8, 0x7f, 0x88, 0xaa, 0x5d, 0xaf, 0xe2, 0xdf, 0x77, 0x96, 0x88, 0xa1, 0x72,
|
||||
0xde, 0xf1, 0x1c, 0x7d, 0x5c, 0xcd, 0xef, 0x13,
|
||||
}
|
||||
if nt != val {
|
||||
t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNTLMSessionResponse(t *testing.T) {
|
||||
challenge := [8]byte{
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
}
|
||||
nonce := [8]byte{
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
}
|
||||
nt := ntlmSessionResponse(nonce, challenge, "Password")
|
||||
val := [24]byte{
|
||||
0x75, 0x37, 0xf8, 0x03, 0xae, 0x36, 0x71, 0x28, 0xca, 0x45, 0x82, 0x04, 0xbd, 0xe7, 0xca, 0xf8,
|
||||
0x1e, 0x97, 0xed, 0x26, 0x83, 0x26, 0x72, 0x32,
|
||||
}
|
||||
if nt != val {
|
||||
t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:]))
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/denisenkom/go-mssqldb/parser_test.go
generated
vendored
60
vendor/github.com/denisenkom/go-mssqldb/parser_test.go
generated
vendored
|
|
@ -1,60 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseParams(t *testing.T) {
|
||||
values := []struct {
|
||||
s string
|
||||
d string
|
||||
n int
|
||||
}{
|
||||
{"select ?", "select @p1", 1},
|
||||
{"select ?, ?", "select @p1, @p2", 2},
|
||||
{"select ? -- ?", "select @p1 -- ?", 1},
|
||||
{"select ? -- ?\n, ?", "select @p1 -- ?\n, @p2", 2},
|
||||
{"select ? - ?", "select @p1 - @p2", 2},
|
||||
{"select ? /* ? */, ?", "select @p1 /* ? */, @p2", 2},
|
||||
{"select ? /* ? * ? */, ?", "select @p1 /* ? * ? */, @p2", 2},
|
||||
{"select \"foo?\", [foo?], 'foo?', ?", "select \"foo?\", [foo?], 'foo?', @p1", 1},
|
||||
{"select \"x\"\"y\", [x]]y], 'x''y', ?", "select \"x\"\"y\", [x]]y], 'x''y', @p1", 1},
|
||||
{"select \"foo?\", ?", "select \"foo?\", @p1", 1},
|
||||
{"select 'foo?', ?", "select 'foo?', @p1", 1},
|
||||
{"select [foo?], ?", "select [foo?], @p1", 1},
|
||||
{"select $1", "select @p1", 1},
|
||||
{"select $1, $2", "select @p1, @p2", 2},
|
||||
{"select $1, $1", "select @p1, @p1", 1},
|
||||
{"select :1", "select @p1", 1},
|
||||
{"select :1, :2", "select @p1, @p2", 2},
|
||||
{"select :1, :1", "select @p1, @p1", 1},
|
||||
{"select ?1", "select @p1", 1},
|
||||
{"select ?1, ?2", "select @p1, @p2", 2},
|
||||
{"select ?1, ?1", "select @p1, @p1", 1},
|
||||
{"select $12", "select @p12", 12},
|
||||
{"select ? /* ? /* ? */ ? */ ?", "select @p1 /* ? /* ? */ ? */ @p2", 2},
|
||||
{"select ? /* ? / ? */ ?", "select @p1 /* ? / ? */ @p2", 2},
|
||||
{"select $", "select $", 0},
|
||||
{"select x::y", "select x:@y", 1},
|
||||
{"select '", "select '", 0},
|
||||
{"select \"", "select \"", 0},
|
||||
{"select [", "select [", 0},
|
||||
{"select []", "select []", 0},
|
||||
{"select -", "select -", 0},
|
||||
{"select /", "select /", 0},
|
||||
{"select 1/1", "select 1/1", 0},
|
||||
{"select /*", "select /*", 0},
|
||||
{"select /**", "select /**", 0},
|
||||
{"select /*/", "select /*/", 0},
|
||||
}
|
||||
|
||||
for _, v := range values {
|
||||
d, n := parseParams(v.s)
|
||||
if d != v.d {
|
||||
t.Errorf("Parse params don't match for %s, got %s but expected %s", v.s, d, v.d)
|
||||
}
|
||||
if n != v.n {
|
||||
t.Errorf("Parse number of params don't match for %s, got %d but expected %d", v.s, n, v.n)
|
||||
}
|
||||
}
|
||||
}
|
||||
189
vendor/github.com/denisenkom/go-mssqldb/queries_go110_test.go
generated
vendored
189
vendor/github.com/denisenkom/go-mssqldb/queries_go110_test.go
generated
vendored
|
|
@ -1,189 +0,0 @@
|
|||
// +build go1.10
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func TestSessionInitSQL(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
|
||||
d := &Driver{}
|
||||
connector, err := d.OpenConnector(makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Fatal("unable to open connector", err)
|
||||
}
|
||||
|
||||
// Do not use these settings in your application
|
||||
// unless you know what they do.
|
||||
// Thes are for this unit test only.
|
||||
//
|
||||
// Sessions will be reset even if SessionInitSQL is not set.
|
||||
connector.SessionInitSQL = `
|
||||
SET XACT_ABORT ON; -- 16384
|
||||
SET ANSI_NULLS ON; -- 32
|
||||
SET ARITHIGNORE ON; -- 128
|
||||
`
|
||||
|
||||
pool := sql.OpenDB(connector)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var opt int32
|
||||
err = pool.QueryRowContext(ctx, `
|
||||
select Options = @@OPTIONS;
|
||||
`).Scan(&opt)
|
||||
if err != nil {
|
||||
t.Fatal("failed to run query", err)
|
||||
}
|
||||
mask := int32(16384 | 128 | 32)
|
||||
|
||||
if opt&mask != mask {
|
||||
t.Fatal("incorrect session settings", opt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParameterTypes(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
pool, err := sql.Open("sqlserver", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var nv, v, nvcm, vcm, dt1, dt2, tm, d, dto string
|
||||
row := pool.QueryRow(`
|
||||
select
|
||||
nv = SQL_VARIANT_PROPERTY(@nv,'BaseType'),
|
||||
v = SQL_VARIANT_PROPERTY(@v,'BaseType'),
|
||||
@nvcm,
|
||||
@vcm,
|
||||
dt1 = SQL_VARIANT_PROPERTY(@dt1,'BaseType'),
|
||||
dt2 = SQL_VARIANT_PROPERTY(@dt2,'BaseType'),
|
||||
d = SQL_VARIANT_PROPERTY(@d,'BaseType'),
|
||||
tm = SQL_VARIANT_PROPERTY(@tm,'BaseType'),
|
||||
dto = SQL_VARIANT_PROPERTY(@dto,'BaseType')
|
||||
;
|
||||
`,
|
||||
sql.Named("nv", "base type nvarchar"),
|
||||
sql.Named("v", VarChar("base type varchar")),
|
||||
sql.Named("nvcm", NVarCharMax(strings.Repeat("x", 5000))),
|
||||
sql.Named("vcm", VarCharMax(strings.Repeat("x", 5000))),
|
||||
sql.Named("dt1", DateTime1(tin)),
|
||||
sql.Named("dt2", civil.DateTimeOf(tin)),
|
||||
sql.Named("d", civil.DateOf(tin)),
|
||||
sql.Named("tm", civil.TimeOf(tin)),
|
||||
sql.Named("dto", DateTimeOffset(tin)),
|
||||
)
|
||||
err = row.Scan(&nv, &v, &nvcm, &vcm, &dt1, &dt2, &d, &tm, &dto)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nv != "nvarchar" {
|
||||
t.Errorf(`want "nvarchar" got %q`, nv)
|
||||
}
|
||||
if v != "varchar" {
|
||||
t.Errorf(`want "varchar" got %q`, v)
|
||||
}
|
||||
if nvcm != strings.Repeat("x", 5000) {
|
||||
t.Errorf(`incorrect value returned for nvarchar(max): %q`, nvcm)
|
||||
}
|
||||
if vcm != strings.Repeat("x", 5000) {
|
||||
t.Errorf(`incorrect value returned for varchar(max): %q`, vcm)
|
||||
}
|
||||
if dt1 != "datetime" {
|
||||
t.Errorf(`want "datetime" got %q`, dt1)
|
||||
}
|
||||
if dt2 != "datetime2" {
|
||||
t.Errorf(`want "datetime2" got %q`, dt2)
|
||||
}
|
||||
if d != "date" {
|
||||
t.Errorf(`want "date" got %q`, d)
|
||||
}
|
||||
if tm != "time" {
|
||||
t.Errorf(`want "time" got %q`, tm)
|
||||
}
|
||||
if dto != "datetimeoffset" {
|
||||
t.Errorf(`want "datetimeoffset" got %q`, dto)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParameterValues(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
pool, err := sql.Open("sqlserver", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
sin := "high five"
|
||||
tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var nv, v, tgo, dt1, dt2, tm, d, dto string
|
||||
err = pool.QueryRow(`
|
||||
select
|
||||
nv = @nv,
|
||||
v = @v,
|
||||
tgo = @tgo,
|
||||
dt1 = convert(nvarchar(200), @dt1, 121),
|
||||
dt2 = convert(nvarchar(200), @dt2, 121),
|
||||
d = convert(nvarchar(200), @d, 121),
|
||||
tm = convert(nvarchar(200), @tm, 121),
|
||||
dto = convert(nvarchar(200), @dto, 121)
|
||||
;
|
||||
`,
|
||||
sql.Named("nv", sin),
|
||||
sql.Named("v", sin),
|
||||
sql.Named("tgo", tin),
|
||||
sql.Named("dt1", DateTime1(tin)),
|
||||
sql.Named("dt2", civil.DateTimeOf(tin)),
|
||||
sql.Named("d", civil.DateOf(tin)),
|
||||
sql.Named("tm", civil.TimeOf(tin)),
|
||||
sql.Named("dto", DateTimeOffset(tin)),
|
||||
).Scan(&nv, &v, &tgo, &dt1, &dt2, &d, &tm, &dto)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := sin; nv != want {
|
||||
t.Errorf(`want %q got %q`, want, nv)
|
||||
}
|
||||
if want := sin; v != want {
|
||||
t.Errorf(`want %q got %q`, want, v)
|
||||
}
|
||||
if want := "2006-01-02T22:04:05-07:00"; tgo != want {
|
||||
t.Errorf(`want %q got %q`, want, tgo)
|
||||
}
|
||||
if want := "2006-01-02 22:04:05.000"; dt1 != want {
|
||||
t.Errorf(`want %q got %q`, want, dt1)
|
||||
}
|
||||
if want := "2006-01-02 22:04:05.0000000"; dt2 != want {
|
||||
t.Errorf(`want %q got %q`, want, dt2)
|
||||
}
|
||||
if want := "2006-01-02"; d != want {
|
||||
t.Errorf(`want %q got %q`, want, d)
|
||||
}
|
||||
if want := "22:04:05.0000000"; tm != want {
|
||||
t.Errorf(`want %q got %q`, want, tm)
|
||||
}
|
||||
if want := "2006-01-02 22:04:05.0000000 -07:00"; dto != want {
|
||||
t.Errorf(`want %q got %q`, want, dto)
|
||||
}
|
||||
}
|
||||
856
vendor/github.com/denisenkom/go-mssqldb/queries_go19_test.go
generated
vendored
856
vendor/github.com/denisenkom/go-mssqldb/queries_go19_test.go
generated
vendored
|
|
@ -1,856 +0,0 @@
|
|||
// +build go1.9
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOutputParam(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
|
||||
db, err := sql.Open("sqlserver", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open driver sqlserver")
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
t.Run("sp with rows", func(t *testing.T) {
|
||||
sqltextcreate := `
|
||||
CREATE PROCEDURE spwithrows
|
||||
@intparam INT = NULL OUTPUT
|
||||
AS
|
||||
BEGIN
|
||||
-- return 2 rows
|
||||
SELECT @intparam
|
||||
union
|
||||
SELECT 20
|
||||
|
||||
-- set output parameter value
|
||||
SELECT @intparam = 10
|
||||
END;
|
||||
`
|
||||
sqltextdrop := `DROP PROCEDURE spwithrows;`
|
||||
sqltextrun := `spwithrows`
|
||||
|
||||
db.ExecContext(ctx, sqltextdrop)
|
||||
_, err = db.ExecContext(ctx, sqltextcreate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.ExecContext(ctx, sqltextdrop)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var intparam int = 5
|
||||
rows, err := db.QueryContext(ctx, sqltextrun,
|
||||
sql.Named("intparam", sql.Out{Dest: &intparam}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// reading first row
|
||||
if !rows.Next() {
|
||||
t.Error("Next returned false")
|
||||
}
|
||||
var rowval int
|
||||
err = rows.Scan(&rowval)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if rowval != 5 {
|
||||
t.Errorf("expected 5, got %d", rowval)
|
||||
}
|
||||
|
||||
// if uncommented would trigger race condition warning
|
||||
//if intparam != 10 {
|
||||
// t.Log("output parameter value is not yet 10, it is ", intparam)
|
||||
//}
|
||||
|
||||
// reading second row
|
||||
if !rows.Next() {
|
||||
t.Error("Next returned false")
|
||||
}
|
||||
err = rows.Scan(&rowval)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if rowval != 20 {
|
||||
t.Errorf("expected 20, got %d", rowval)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Error("Next returned true but should return false after last row was returned")
|
||||
}
|
||||
|
||||
if intparam != 10 {
|
||||
t.Errorf("expected 10, got %d", intparam)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("sp with no rows", func(t *testing.T) {
|
||||
sqltextcreate := `
|
||||
CREATE PROCEDURE abassign
|
||||
@aid INT = 5,
|
||||
@bid INT = NULL OUTPUT,
|
||||
@cstr NVARCHAR(2000) = NULL OUTPUT,
|
||||
@datetime datetime = NULL OUTPUT
|
||||
AS
|
||||
BEGIN
|
||||
SELECT @bid = @aid, @cstr = 'OK', @datetime = '2010-01-01T00:00:00';
|
||||
END;
|
||||
`
|
||||
sqltextdrop := `DROP PROCEDURE abassign;`
|
||||
sqltextrun := `abassign`
|
||||
|
||||
db.ExecContext(ctx, sqltextdrop)
|
||||
_, err = db.ExecContext(ctx, sqltextcreate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.ExecContext(ctx, sqltextdrop)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Run("should work", func(t *testing.T) {
|
||||
var bout int64
|
||||
var cout string
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("aid", 5),
|
||||
sql.Named("bid", sql.Out{Dest: &bout}),
|
||||
sql.Named("cstr", sql.Out{Dest: &cout}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bout != 5 {
|
||||
t.Errorf("expected 5, got %d", bout)
|
||||
}
|
||||
|
||||
if cout != "OK" {
|
||||
t.Errorf("expected OK, got %s", cout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should work if aid is not passed", func(t *testing.T) {
|
||||
var bout int64
|
||||
var cout string
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: &bout}),
|
||||
sql.Named("cstr", sql.Out{Dest: &cout}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bout != 5 {
|
||||
t.Errorf("expected 5, got %d", bout)
|
||||
}
|
||||
|
||||
if cout != "OK" {
|
||||
t.Errorf("expected OK, got %s", cout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should work for DateTime1 parameter", func(t *testing.T) {
|
||||
tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected, err := time.Parse(time.RFC3339, "2010-01-01T00:00:00-00:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var datetime_param DateTime1
|
||||
datetime_param = DateTime1(tin)
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("datetime", sql.Out{Dest: &datetime_param}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if time.Time(datetime_param).UTC() != expected.UTC() {
|
||||
t.Errorf("Datetime returned '%v' does not match expected value '%v'",
|
||||
time.Time(datetime_param).UTC(), expected.UTC())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("destination is not a pointer", func(t *testing.T) {
|
||||
var int_out int64
|
||||
var str_out string
|
||||
// test when destination is not a pointer
|
||||
_, actual := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: int_out}),
|
||||
sql.Named("cstr", sql.Out{Dest: &str_out}),
|
||||
)
|
||||
pattern := ".*destination not a pointer.*"
|
||||
match, err := regexp.MatchString(pattern, actual.Error())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should convert int64 to int", func(t *testing.T) {
|
||||
var bout int
|
||||
var cout string
|
||||
_, err := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: &bout}),
|
||||
sql.Named("cstr", sql.Out{Dest: &cout}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bout != 5 {
|
||||
t.Errorf("expected 5, got %d", bout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should fail if destination has invalid type", func(t *testing.T) {
|
||||
// Error type should not be supported
|
||||
var err_out Error
|
||||
_, err := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: &err_out}),
|
||||
)
|
||||
if err == nil {
|
||||
t.Error("Expected to fail but it didn't")
|
||||
}
|
||||
|
||||
// double inderection should not work
|
||||
var out_out = sql.Out{Dest: &err_out}
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: out_out}),
|
||||
)
|
||||
if err == nil {
|
||||
t.Error("Expected to fail but it didn't")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should fail if parameter has invalid type", func(t *testing.T) {
|
||||
// passing invalid parameter type
|
||||
var err_val Error
|
||||
_, err = db.ExecContext(ctx, sqltextrun, err_val)
|
||||
if err == nil {
|
||||
t.Error("Expected to fail but it didn't")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("destination is a nil pointer", func(t *testing.T) {
|
||||
var str_out string
|
||||
// test when destination is nil pointer
|
||||
_, actual := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: nil}),
|
||||
sql.Named("cstr", sql.Out{Dest: &str_out}),
|
||||
)
|
||||
pattern := ".*destination is a nil pointer.*"
|
||||
match, err := regexp.MatchString(pattern, actual.Error())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("destination is a nil pointer 2", func(t *testing.T) {
|
||||
var int_ptr *int
|
||||
_, actual := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: int_ptr}),
|
||||
)
|
||||
pattern := ".*destination is a nil pointer.*"
|
||||
match, err := regexp.MatchString(pattern, actual.Error())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pointer to a pointer", func(t *testing.T) {
|
||||
var str_out *string
|
||||
_, actual := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("cstr", sql.Out{Dest: &str_out}),
|
||||
)
|
||||
pattern := ".*destination is a pointer to a pointer.*"
|
||||
match, err := regexp.MatchString(pattern, actual.Error())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestOutputINOUTParam(t *testing.T) {
|
||||
sqltextcreate := `
|
||||
CREATE PROCEDURE abinout
|
||||
@aid INT = 1,
|
||||
@bid INT = 2 OUTPUT,
|
||||
@cstr NVARCHAR(2000) = NULL OUTPUT,
|
||||
@vout VARCHAR(2000) = NULL OUTPUT,
|
||||
@nullint INT = NULL OUTPUT,
|
||||
@nullfloat FLOAT = NULL OUTPUT,
|
||||
@nullstr NVARCHAR(10) = NULL OUTPUT,
|
||||
@nullbit BIT = NULL OUTPUT,
|
||||
@varbin VARBINARY(10) = NULL OUTPUT
|
||||
AS
|
||||
BEGIN
|
||||
SELECT
|
||||
@bid = @aid + @bid,
|
||||
@cstr = 'OK',
|
||||
@Vout = 'DREAM'
|
||||
;
|
||||
END;
|
||||
`
|
||||
sqltextdrop := `DROP PROCEDURE abinout;`
|
||||
sqltextrun := `abinout`
|
||||
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
|
||||
db, err := sql.Open("sqlserver", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open driver sqlserver")
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
db.ExecContext(ctx, sqltextdrop)
|
||||
_, err = db.ExecContext(ctx, sqltextcreate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.ExecContext(ctx, sqltextdrop)
|
||||
|
||||
t.Run("original test", func(t *testing.T) {
|
||||
var bout int64 = 3
|
||||
var cout string
|
||||
var vout VarChar
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("aid", 5),
|
||||
sql.Named("bid", sql.Out{Dest: &bout}),
|
||||
sql.Named("cstr", sql.Out{Dest: &cout}),
|
||||
sql.Named("vout", sql.Out{Dest: &vout}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bout != 8 {
|
||||
t.Errorf("expected 8, got %d", bout)
|
||||
}
|
||||
|
||||
if cout != "OK" {
|
||||
t.Errorf("expected OK, got %s", cout)
|
||||
}
|
||||
if string(vout) != "DREAM" {
|
||||
t.Errorf("expected DREAM, got %s", vout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test null values returned into nullable", func(t *testing.T) {
|
||||
var nullint sql.NullInt64
|
||||
var nullfloat sql.NullFloat64
|
||||
var nullstr sql.NullString
|
||||
var nullbit sql.NullBool
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("nullint", sql.Out{Dest: &nullint}),
|
||||
sql.Named("nullfloat", sql.Out{Dest: &nullfloat}),
|
||||
sql.Named("nullstr", sql.Out{Dest: &nullstr}),
|
||||
sql.Named("nullbit", sql.Out{Dest: &nullbit}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if nullint.Valid {
|
||||
t.Errorf("expected NULL, got %v", nullint)
|
||||
}
|
||||
if nullfloat.Valid {
|
||||
t.Errorf("expected NULL, got %v", nullfloat)
|
||||
}
|
||||
if nullstr.Valid {
|
||||
t.Errorf("expected NULL, got %v", nullstr)
|
||||
}
|
||||
if nullbit.Valid {
|
||||
t.Errorf("expected NULL, got %v", nullbit)
|
||||
}
|
||||
})
|
||||
|
||||
// Not yet supported
|
||||
//t.Run("test null values returned into pointers", func(t *testing.T) {
|
||||
// var nullint *int64
|
||||
// var nullfloat *float64
|
||||
// var nullstr *string
|
||||
// var nullbit *bool
|
||||
// _, err = db.ExecContext(ctx, sqltextrun,
|
||||
// sql.Named("nullint", sql.Out{Dest: &nullint}),
|
||||
// sql.Named("nullfloat", sql.Out{Dest: &nullfloat}),
|
||||
// sql.Named("nullstr", sql.Out{Dest: &nullstr}),
|
||||
// sql.Named("nullbit", sql.Out{Dest: &nullbit}),
|
||||
// )
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// }
|
||||
|
||||
// if nullint != nil {
|
||||
// t.Errorf("expected NULL, got %v", nullint)
|
||||
// }
|
||||
// if nullfloat != nil {
|
||||
// t.Errorf("expected NULL, got %v", nullfloat)
|
||||
// }
|
||||
// if nullstr != nil {
|
||||
// t.Errorf("expected NULL, got %v", nullstr)
|
||||
// }
|
||||
// if nullbit != nil {
|
||||
// t.Errorf("expected NULL, got %v", nullbit)
|
||||
// }
|
||||
//})
|
||||
|
||||
t.Run("test non null values into nullable", func(t *testing.T) {
|
||||
nullint := sql.NullInt64{10, true}
|
||||
nullfloat := sql.NullFloat64{1.5, true}
|
||||
nullstr := sql.NullString{"hello", true}
|
||||
nullbit := sql.NullBool{true, true}
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("nullint", sql.Out{Dest: &nullint}),
|
||||
sql.Named("nullfloat", sql.Out{Dest: &nullfloat}),
|
||||
sql.Named("nullstr", sql.Out{Dest: &nullstr}),
|
||||
sql.Named("nullbit", sql.Out{Dest: &nullbit}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !nullint.Valid {
|
||||
t.Error("expected non null value, but got null")
|
||||
}
|
||||
if nullint.Int64 != 10 {
|
||||
t.Errorf("expected 10, got %d", nullint.Int64)
|
||||
}
|
||||
if !nullfloat.Valid {
|
||||
t.Error("expected non null value, but got null")
|
||||
}
|
||||
if nullfloat.Float64 != 1.5 {
|
||||
t.Errorf("expected 1.5, got %v", nullfloat.Float64)
|
||||
}
|
||||
if !nullstr.Valid {
|
||||
t.Error("expected non null value, but got null")
|
||||
}
|
||||
if nullstr.String != "hello" {
|
||||
t.Errorf("expected hello, got %s", nullstr.String)
|
||||
}
|
||||
})
|
||||
t.Run("test return into byte[]", func(t *testing.T) {
|
||||
cstr := []byte{1, 2, 3}
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("varbin", sql.Out{Dest: &cstr}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
expected := []byte{1, 2, 3}
|
||||
if bytes.Compare(cstr, expected) != 0 {
|
||||
t.Errorf("expected [1,2,3], got %v", cstr)
|
||||
}
|
||||
})
|
||||
t.Run("test int into string", func(t *testing.T) {
|
||||
var str string
|
||||
_, err = db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: &str}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if str != "1" {
|
||||
t.Errorf("expected '1', got %v", str)
|
||||
}
|
||||
})
|
||||
t.Run("typeless null for output parameter should return error", func(t *testing.T) {
|
||||
var val interface{}
|
||||
_, actual := db.ExecContext(ctx, sqltextrun,
|
||||
sql.Named("bid", sql.Out{Dest: &val}),
|
||||
)
|
||||
if actual == nil {
|
||||
t.Error("Expected to fail but didn't")
|
||||
}
|
||||
pattern := ".*MSSQL does not allow NULL value without type for OUTPUT parameters.*"
|
||||
match, err := regexp.MatchString(pattern, actual.Error())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestTLSServerReadClose tests writing to an encrypted database connection.
|
||||
// Currently the database server will close the connection while the server is
|
||||
// reading the TDS packets and before any of the data has been parsed.
|
||||
//
|
||||
// When two queries are sent in reverse order, they PASS, but if we send only
|
||||
// a single ping (SELECT 1;) first, then the long query the query fails.
|
||||
//
|
||||
// The long query text is never parsed. In fact, you can comment out, return
|
||||
// early, or have malformed sql in the long query text. Just the length matters.
|
||||
// The error happens when sending the TDS Batch packet to SQL Server the server
|
||||
// closes the connection..
|
||||
//
|
||||
// It appears the driver sends valid TDS packets. In fact, if prefixed with 4
|
||||
// "SELECT 1;" TDS Batch queries then the long query works, but if zero or one
|
||||
// "SELECT 1;" TDS Batch queries are send prior the long query fails to send.
|
||||
//
|
||||
// Lastly, this only manafests itself with an encrypted connection. This has been
|
||||
// observed with SQL Server Azure, SQL Server 13.0.1742 on Windows, and SQL Server
|
||||
// 14.0.900.75 on Linux. It also fails when using the "dev.boringcrypto" (a C based
|
||||
// TLS crypto). I haven't found any knobs on SQL Server to expose the error message
|
||||
// nor have I found a good way to decrypt the TDS stream. KeyLogWriter in the TLS
|
||||
// config may help with that, but wireshark wasn't decrypting TDS based TLS streams
|
||||
// even when using that.
|
||||
//
|
||||
// Issue https://github.com/denisenkom/go-mssqldb/issues/166
|
||||
func TestTLSServerReadClose(t *testing.T) {
|
||||
query := `
|
||||
with
|
||||
config_cte (config) as (
|
||||
select *
|
||||
from ( values
|
||||
('_partition:{\"Fill\":{\"PatternType\":\"solid\",\"FgColor\":\"99ff99\"}}')
|
||||
, ('_separation:{\"Fill\":{\"PatternType\":\"solid\",\"FgColor\":\"99ffff\"}}')
|
||||
, ('Monthly Earnings:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Weekly Earnings:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Total Earnings:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Average Earnings:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Last Month Earning:#,##0.00 ;(#,##0.00)')
|
||||
, ('Award:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Amount:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Grand Total:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Total:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Price Each:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Hyperwallet:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Credit/Debit:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Earning:#,##0.00 ;(#,##0.00)')
|
||||
, ('Change Earning:#,##0.00 ;(#,##0.00)')
|
||||
, ('CheckAmount:#,##0.00 ;(#,##0.00)')
|
||||
, ('Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Prev Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Team Bonuses:#,##0.00 ;(#,##0.00)')
|
||||
, ('Change:#,##0.00 ;(#,##0.00)')
|
||||
, ('Shipping Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('SubTotal:\$#,##0.00 ;(\$#,##0.00)')
|
||||
, ('Total Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('SubTotal Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Return Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Return SubTotal:#,##0.00 ;(#,##0.00)')
|
||||
, ('Return Total Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Return SubTotal Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Cancel Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Cancel SubTotal:#,##0.00 ;(#,##0.00)')
|
||||
, ('Cancel Total Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Cancel SubTotal Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Replacement Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Replacement SubTotal:#,##0.00 ;(#,##0.00)')
|
||||
, ('Replacement Total Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Replacement SubTotal Diff:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('January Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('February Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('March Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('April Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('June Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('July Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('August Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('September Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('October Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('November Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('December Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('January Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('February Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('March Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('April Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('June Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('July Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('August Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('September Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('October Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('November Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('December Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('January Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('February Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('March Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('April Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('June Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('July Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('August Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('September Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('October Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('November Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('December Adj:#,##0.00 ;(#,##0.00)')
|
||||
, ('2016- 2015 YTD Dif:#,##0.00 ;(#,##0.00)')
|
||||
, ('2017- 2016 YTD Dif:#,##0.00 ;(#,##0.00)')
|
||||
, ('2018- 2017 YTD Dif:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec to Jan Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan to Feb Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb to Mar Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar to Apr Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr to May Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('May to Jun Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun to Jul Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul to Aug Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug to Sep Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep to Oct Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct to Nov Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov to Dec Dif Residual:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec to Jan Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan to Feb Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb to Mar Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar to Apr Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr to May Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('May to Jun Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun to Jul Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul to Aug Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug to Sep Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep to Oct Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct to Nov Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov to Dec Dif Bonus:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec to Jan Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan to Feb Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb to Mar Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar to Apr Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr to May Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('May to Jun Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun to Jul Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul to Aug Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug to Sep Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep to Oct Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct to Nov Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov to Dec Dif Total:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Feb Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Mar Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Apr Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('May Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jun Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jul Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Aug Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Sep Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Oct Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Nov Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Dec Refund Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jan Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Feb Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Mar Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Apr Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('May Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jun Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jul Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Aug Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Sep Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Oct Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Nov Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Dec Purchase Cnt:#,##0 ;(#,##0)')
|
||||
, ('Jan Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec Refund Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jan Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Feb Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Mar Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Apr Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('May Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jun Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Jul Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Aug Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Sep Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Oct Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Nov Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
, ('Dec Purchase Amt:#,##0.00 ;(#,##0.00)')
|
||||
) X(a))
|
||||
select * from config_cte
|
||||
`
|
||||
t.Logf("query len (utf16 bytes)=%d, len/4096=%f\n", len(query)*2, float64(len(query)*2)/4096)
|
||||
|
||||
db := open(t)
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
type run struct {
|
||||
name string
|
||||
pings []int
|
||||
pass bool
|
||||
|
||||
conn *sql.Conn
|
||||
}
|
||||
|
||||
// Use separate Conns from the connection pool to ensure separation.
|
||||
runs := []*run{
|
||||
{name: "rev", pings: []int{4, 1}, pass: true},
|
||||
{name: "forward", pings: []int{1}, pass: true},
|
||||
}
|
||||
for _, r := range runs {
|
||||
var err error
|
||||
r.conn, err = db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer r.conn.Close()
|
||||
}
|
||||
|
||||
for _, r := range runs {
|
||||
for _, ping := range r.pings {
|
||||
t.Run(fmt.Sprintf("%s-ping-%d", r.name, ping), func(t *testing.T) {
|
||||
for i := 0; i < ping; i++ {
|
||||
if err := r.conn.PingContext(ctx); err != nil {
|
||||
if r.pass {
|
||||
t.Error("failed to ping server", err)
|
||||
} else {
|
||||
t.Log("failed to ping server", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := r.conn.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
if r.pass {
|
||||
t.Errorf("QueryContext: %+v", err)
|
||||
} else {
|
||||
t.Logf("QueryContext: %+v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
// Nothing.
|
||||
}
|
||||
rows.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeParam19(t *testing.T) {
|
||||
conn := open(t)
|
||||
defer conn.Close()
|
||||
|
||||
// testing DateTime1, only supported on go 1.9
|
||||
var emptydate time.Time
|
||||
mindate1 := time.Date(1753, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
maxdate1 := time.Date(9999, 12, 31, 23, 59, 59, 997000000, time.UTC)
|
||||
testdates1 := []DateTime1{
|
||||
DateTime1(mindate1),
|
||||
DateTime1(maxdate1),
|
||||
DateTime1(time.Date(1752, 12, 31, 23, 59, 59, 997000000, time.UTC)), // just a little below minimum date
|
||||
DateTime1(time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC)), // just a little over maximum date
|
||||
DateTime1(emptydate),
|
||||
}
|
||||
|
||||
for _, test := range testdates1 {
|
||||
t.Run(fmt.Sprintf("Test datetime for %v", test), func(t *testing.T) {
|
||||
var res time.Time
|
||||
expected := time.Time(test)
|
||||
queryParamRoundTrip(conn, test, &res)
|
||||
// clip value
|
||||
if expected.Before(mindate1) {
|
||||
expected = mindate1
|
||||
}
|
||||
if expected.After(maxdate1) {
|
||||
expected = maxdate1
|
||||
}
|
||||
if expected.Sub(res) != 0 {
|
||||
t.Errorf("expected: '%s', got: '%s' delta: %d", expected, res, expected.Sub(res))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReturnStatus(t *testing.T) {
|
||||
conn := open(t)
|
||||
defer conn.Close()
|
||||
|
||||
_, err := conn.Exec("if object_id('retstatus') is not null drop proc retstatus;")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = conn.Exec("create proc retstatus as return 2;")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var rs ReturnStatus
|
||||
_, err = conn.Exec("retstatus", &rs)
|
||||
conn.Exec("drop proc retstatus;")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rs != 2 {
|
||||
t.Errorf("expected status=2, got %d", rs)
|
||||
}
|
||||
}
|
||||
2186
vendor/github.com/denisenkom/go-mssqldb/queries_test.go
generated
vendored
2186
vendor/github.com/denisenkom/go-mssqldb/queries_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
522
vendor/github.com/denisenkom/go-mssqldb/tds_test.go
generated
vendored
522
vendor/github.com/denisenkom/go-mssqldb/tds_test.go
generated
vendored
|
|
@ -1,522 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockTransport struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (t *MockTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestSendLogin(t *testing.T) {
|
||||
memBuf := new(MockTransport)
|
||||
buf := newTdsBuffer(1024, memBuf)
|
||||
login := login{
|
||||
TDSVersion: verTDS73,
|
||||
PacketSize: 0x1000,
|
||||
ClientProgVer: 0x01060100,
|
||||
ClientPID: 100,
|
||||
ClientTimeZone: -4 * 60,
|
||||
ClientID: [6]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab},
|
||||
OptionFlags1: 0xe0,
|
||||
OptionFlags3: 8,
|
||||
HostName: "subdev1",
|
||||
UserName: "test",
|
||||
Password: "testpwd",
|
||||
AppName: "appname",
|
||||
ServerName: "servername",
|
||||
CtlIntName: "library",
|
||||
Language: "en",
|
||||
Database: "database",
|
||||
ClientLCID: 0x204,
|
||||
AtchDBFile: "filepath",
|
||||
}
|
||||
err := sendLogin(buf, login)
|
||||
if err != nil {
|
||||
t.Error("sendLogin should succeed")
|
||||
}
|
||||
ref := []byte{
|
||||
16, 1, 0, 222, 0, 0, 1, 0, 198 + 16, 0, 0, 0, 3, 0, 10, 115, 0, 16, 0, 0, 0, 1,
|
||||
6, 1, 100, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 8, 16, 255, 255, 255, 4, 2, 0,
|
||||
0, 94, 0, 7, 0, 108, 0, 4, 0, 116, 0, 7, 0, 130, 0, 7, 0, 144, 0, 10, 0, 0,
|
||||
0, 0, 0, 164, 0, 7, 0, 178, 0, 2, 0, 182, 0, 8, 0, 18, 52, 86, 120, 144, 171,
|
||||
198, 0, 0, 0, 198, 0, 8, 0, 214, 0, 0, 0, 0, 0, 0, 0, 115, 0, 117, 0, 98,
|
||||
0, 100, 0, 101, 0, 118, 0, 49, 0, 116, 0, 101, 0, 115, 0, 116, 0, 226, 165,
|
||||
243, 165, 146, 165, 226, 165, 162, 165, 210, 165, 227, 165, 97, 0, 112,
|
||||
0, 112, 0, 110, 0, 97, 0, 109, 0, 101, 0, 115, 0, 101, 0, 114, 0, 118, 0,
|
||||
101, 0, 114, 0, 110, 0, 97, 0, 109, 0, 101, 0, 108, 0, 105, 0, 98, 0, 114,
|
||||
0, 97, 0, 114, 0, 121, 0, 101, 0, 110, 0, 100, 0, 97, 0, 116, 0, 97, 0, 98,
|
||||
0, 97, 0, 115, 0, 101, 0, 102, 0, 105, 0, 108, 0, 101, 0, 112, 0, 97, 0,
|
||||
116, 0, 104, 0}
|
||||
out := memBuf.Bytes()
|
||||
if !bytes.Equal(ref, out) {
|
||||
fmt.Println("Expected:")
|
||||
fmt.Print(hex.Dump(ref))
|
||||
fmt.Println("Returned:")
|
||||
fmt.Print(hex.Dump(out))
|
||||
t.Error("input output don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendSqlBatch(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
p, err := parseConnectParams(makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Error("parseConnectParams failed:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := connect(context.Background(), nil, optionalLogger{testLogger{t}}, p)
|
||||
if err != nil {
|
||||
t.Error("Open connection failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.buf.transport.Close()
|
||||
|
||||
headers := []headerStruct{
|
||||
{hdrtype: dataStmHdrTransDescr,
|
||||
data: transDescrHdr{0, 1}.pack()},
|
||||
}
|
||||
err = sendSqlBatch72(conn.buf, "select 1", headers, true)
|
||||
if err != nil {
|
||||
t.Error("Sending sql batch failed", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ch := make(chan tokenStruct, 5)
|
||||
go processResponse(context.Background(), conn, ch, nil)
|
||||
|
||||
var lastRow []interface{}
|
||||
loop:
|
||||
for tok := range ch {
|
||||
switch token := tok.(type) {
|
||||
case doneStruct:
|
||||
break loop
|
||||
case []columnStruct:
|
||||
conn.columns = token
|
||||
case []interface{}:
|
||||
lastRow = token
|
||||
default:
|
||||
fmt.Println("unknown token", tok)
|
||||
}
|
||||
}
|
||||
|
||||
if len(lastRow) == 0 {
|
||||
t.Fatal("expected row but no row set")
|
||||
}
|
||||
|
||||
switch value := lastRow[0].(type) {
|
||||
case int32:
|
||||
if value != 1 {
|
||||
t.Error("Invalid value returned, should be 1", value)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkConnStr(t *testing.T) {
|
||||
if len(os.Getenv("SQLSERVER_DSN")) > 0 {
|
||||
return
|
||||
}
|
||||
if len(os.Getenv("HOST")) > 0 && len(os.Getenv("DATABASE")) > 0 {
|
||||
return
|
||||
}
|
||||
t.Skip("no database connection string")
|
||||
}
|
||||
|
||||
// makeConnStr returns a URL struct so it may be modified by various
|
||||
// tests before used as a DSN.
|
||||
func makeConnStr(t *testing.T) *url.URL {
|
||||
dsn := os.Getenv("SQLSERVER_DSN")
|
||||
if len(dsn) > 0 {
|
||||
parsed, err := url.Parse(dsn)
|
||||
if err != nil {
|
||||
t.Fatal("unable to parse SQLSERVER_DSN as URL", err)
|
||||
}
|
||||
values := parsed.Query()
|
||||
if values.Get("log") == "" {
|
||||
values.Set("log", "127")
|
||||
}
|
||||
parsed.RawQuery = values.Encode()
|
||||
return parsed
|
||||
}
|
||||
values := url.Values{}
|
||||
values.Set("log", "127")
|
||||
values.Set("database", os.Getenv("DATABASE"))
|
||||
return &url.URL{
|
||||
Scheme: "sqlserver",
|
||||
Host: os.Getenv("HOST"),
|
||||
Path: os.Getenv("INSTANCE"),
|
||||
User: url.UserPassword(os.Getenv("SQLUSER"), os.Getenv("SQLPASSWORD")),
|
||||
RawQuery: values.Encode(),
|
||||
}
|
||||
}
|
||||
|
||||
type testLogger struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (l testLogger) Printf(format string, v ...interface{}) {
|
||||
l.t.Logf(format, v...)
|
||||
}
|
||||
|
||||
func (l testLogger) Println(v ...interface{}) {
|
||||
l.t.Log(v...)
|
||||
}
|
||||
|
||||
func open(t *testing.T) *sql.DB {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
conn, err := sql.Open("mssql", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Error("Open connection failed:", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
conn, err := sql.Open("mssql", makeConnStr(t).String())
|
||||
if err != nil {
|
||||
t.Error("Open connection failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
}
|
||||
|
||||
func simpleQuery(conn *sql.DB, t *testing.T) (stmt *sql.Stmt) {
|
||||
stmt, err := conn.Prepare("select 1 as a")
|
||||
if err != nil {
|
||||
t.Error("Prepare failed:", err.Error())
|
||||
return nil
|
||||
}
|
||||
return stmt
|
||||
}
|
||||
|
||||
func checkSimpleQuery(rows *sql.Rows, t *testing.T) {
|
||||
numrows := 0
|
||||
for rows.Next() {
|
||||
var val int
|
||||
err := rows.Scan(&val)
|
||||
if err != nil {
|
||||
t.Error("Scan failed:", err.Error())
|
||||
}
|
||||
if val != 1 {
|
||||
t.Error("query should return 1")
|
||||
}
|
||||
numrows++
|
||||
}
|
||||
if numrows != 1 {
|
||||
t.Error("query should return 1 row, returned", numrows)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
conn := open(t)
|
||||
if conn == nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
stmt := simpleQuery(conn, t)
|
||||
if stmt == nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows, err := stmt.Query()
|
||||
if err != nil {
|
||||
t.Error("Query failed:", err.Error())
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
t.Error("getting columns failed", err.Error())
|
||||
}
|
||||
if len(columns) != 1 && columns[0] != "a" {
|
||||
t.Error("returned incorrect columns (expected ['a']):", columns)
|
||||
}
|
||||
|
||||
checkSimpleQuery(rows, t)
|
||||
}
|
||||
|
||||
func TestMultipleQueriesSequentialy(t *testing.T) {
|
||||
|
||||
conn := open(t)
|
||||
defer conn.Close()
|
||||
|
||||
stmt, err := conn.Prepare("select 1 as a")
|
||||
if err != nil {
|
||||
t.Error("Prepare failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows, err := stmt.Query()
|
||||
if err != nil {
|
||||
t.Error("Query failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
checkSimpleQuery(rows, t)
|
||||
|
||||
rows, err = stmt.Query()
|
||||
if err != nil {
|
||||
t.Error("Query failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
checkSimpleQuery(rows, t)
|
||||
}
|
||||
|
||||
func TestMultipleQueryClose(t *testing.T) {
|
||||
conn := open(t)
|
||||
defer conn.Close()
|
||||
|
||||
stmt, err := conn.Prepare("select 1 as a")
|
||||
if err != nil {
|
||||
t.Error("Prepare failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows, err := stmt.Query()
|
||||
if err != nil {
|
||||
t.Error("Query failed:", err.Error())
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
rows, err = stmt.Query()
|
||||
if err != nil {
|
||||
t.Error("Query failed:", err.Error())
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
checkSimpleQuery(rows, t)
|
||||
}
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
conn := open(t)
|
||||
defer conn.Close()
|
||||
conn.Ping()
|
||||
}
|
||||
|
||||
func TestSecureWithInvalidHostName(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
|
||||
dsn := makeConnStr(t)
|
||||
dsnParams := dsn.Query()
|
||||
dsnParams.Set("encrypt", "true")
|
||||
dsnParams.Set("TrustServerCertificate", "false")
|
||||
dsnParams.Set("hostNameInCertificate", "foo.bar")
|
||||
dsn.RawQuery = dsnParams.Encode()
|
||||
|
||||
conn, err := sql.Open("mssql", dsn.String())
|
||||
if err != nil {
|
||||
t.Fatal("Open connection failed:", err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
err = conn.Ping()
|
||||
if err == nil {
|
||||
t.Fatal("Connected to fake foo.bar server")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecureConnection(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
|
||||
dsn := makeConnStr(t)
|
||||
dsnParams := dsn.Query()
|
||||
dsnParams.Set("encrypt", "true")
|
||||
dsnParams.Set("TrustServerCertificate", "true")
|
||||
dsn.RawQuery = dsnParams.Encode()
|
||||
|
||||
conn, err := sql.Open("mssql", dsn.String())
|
||||
if err != nil {
|
||||
t.Fatal("Open connection failed:", err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
var msg string
|
||||
err = conn.QueryRow("select 'secret'").Scan(&msg)
|
||||
if err != nil {
|
||||
t.Fatal("cannot scan value", err)
|
||||
}
|
||||
if msg != "secret" {
|
||||
t.Fatal("expected secret, got: ", msg)
|
||||
}
|
||||
var secure bool
|
||||
err = conn.QueryRow("select encrypt_option from sys.dm_exec_connections where session_id=@@SPID").Scan(&secure)
|
||||
if err != nil {
|
||||
t.Fatal("cannot scan value", err)
|
||||
}
|
||||
if !secure {
|
||||
t.Fatal("connection is not encrypted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidConnectionString(t *testing.T) {
|
||||
connStrings := []string{
|
||||
"log=invalid",
|
||||
"port=invalid",
|
||||
"packet size=invalid",
|
||||
"connection timeout=invalid",
|
||||
"dial timeout=invalid",
|
||||
"keepalive=invalid",
|
||||
"encrypt=invalid",
|
||||
"trustservercertificate=invalid",
|
||||
"failoverport=invalid",
|
||||
|
||||
// ODBC mode
|
||||
"odbc:password={",
|
||||
"odbc:password={somepass",
|
||||
"odbc:password={somepass}}",
|
||||
"odbc:password={some}pass",
|
||||
}
|
||||
for _, connStr := range connStrings {
|
||||
_, err := parseConnectParams(connStr)
|
||||
if err == nil {
|
||||
t.Errorf("Connection expected to fail for connection string %s but it didn't", connStr)
|
||||
continue
|
||||
} else {
|
||||
t.Logf("Connection failed for %s as expected with error %v", connStr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidConnectionString(t *testing.T) {
|
||||
type testStruct struct {
|
||||
connStr string
|
||||
check func(connectParams) bool
|
||||
}
|
||||
connStrings := []testStruct{
|
||||
{"server=server\\instance;database=testdb;user id=tester;password=pwd", func(p connectParams) bool {
|
||||
return p.host == "server" && p.instance == "instance" && p.user == "tester" && p.password == "pwd"
|
||||
}},
|
||||
{"server=.", func(p connectParams) bool { return p.host == "localhost" }},
|
||||
{"server=(local)", func(p connectParams) bool { return p.host == "localhost" }},
|
||||
{"ServerSPN=serverspn;Workstation ID=workstid", func(p connectParams) bool { return p.serverSPN == "serverspn" && p.workstation == "workstid" }},
|
||||
{"failoverpartner=fopartner;failoverport=2000", func(p connectParams) bool { return p.failOverPartner == "fopartner" && p.failOverPort == 2000 }},
|
||||
{"app name=appname;applicationintent=ReadOnly", func(p connectParams) bool { return p.appname == "appname" && (p.typeFlags&fReadOnlyIntent != 0) }},
|
||||
{"encrypt=disable", func(p connectParams) bool { return p.disableEncryption }},
|
||||
{"encrypt=true", func(p connectParams) bool { return p.encrypt && !p.disableEncryption }},
|
||||
{"encrypt=false", func(p connectParams) bool { return !p.encrypt && !p.disableEncryption }},
|
||||
{"trustservercertificate=true", func(p connectParams) bool { return p.trustServerCertificate }},
|
||||
{"trustservercertificate=false", func(p connectParams) bool { return !p.trustServerCertificate }},
|
||||
{"certificate=abc", func(p connectParams) bool { return p.certificate == "abc" }},
|
||||
{"hostnameincertificate=abc", func(p connectParams) bool { return p.hostInCertificate == "abc" }},
|
||||
{"connection timeout=3;dial timeout=4;keepalive=5", func(p connectParams) bool {
|
||||
return p.conn_timeout == 3*time.Second && p.dial_timeout == 4*time.Second && p.keepAlive == 5*time.Second
|
||||
}},
|
||||
{"log=63", func(p connectParams) bool { return p.logFlags == 63 && p.port == 1433 }},
|
||||
{"log=63;port=1000", func(p connectParams) bool { return p.logFlags == 63 && p.port == 1000 }},
|
||||
{"log=64", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 4096 }},
|
||||
{"log=64;packet size=0", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 512 }},
|
||||
{"log=64;packet size=300", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 512 }},
|
||||
{"log=64;packet size=8192", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 8192 }},
|
||||
{"log=64;packet size=48000", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 32767 }},
|
||||
|
||||
// those are supported currently, but maybe should not be
|
||||
{"someparam", func(p connectParams) bool { return true }},
|
||||
{";;=;", func(p connectParams) bool { return true }},
|
||||
|
||||
// ODBC mode
|
||||
{"odbc:server=somehost;user id=someuser;password=somepass", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "somepass"
|
||||
}},
|
||||
{"odbc:server=somehost;user id=someuser;password=some{pass", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some{pass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={somepass}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "somepass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={some=pass}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some=pass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={some;pass}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some;pass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={some{pass}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some{pass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={some}}pass}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some}pass"
|
||||
}},
|
||||
{"odbc:server={somehost};user id={someuser};password={some{}}p=a;ss}", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some{}p=a;ss"
|
||||
}},
|
||||
{"odbc: server = somehost; user id = someuser ; password = {some pass } ", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.user == "someuser" && p.password == "some pass "
|
||||
}},
|
||||
|
||||
// URL mode
|
||||
{"sqlserver://somehost?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
{"sqlserver://someuser@somehost?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
{"sqlserver://someuser:@somehost?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
{"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
{"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost:1434?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1434 && p.instance == "" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
{"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost:1434/someinstance?connection+timeout=30", func(p connectParams) bool {
|
||||
return p.host == "somehost" && p.port == 1434 && p.instance == "someinstance" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second
|
||||
}},
|
||||
}
|
||||
for _, ts := range connStrings {
|
||||
p, err := parseConnectParams(ts.connStr)
|
||||
if err == nil {
|
||||
t.Logf("Connection string was parsed successfully %s", ts.connStr)
|
||||
} else {
|
||||
t.Errorf("Connection string %s failed to parse with error %s", ts.connStr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !ts.check(p) {
|
||||
t.Errorf("Check failed on conn str %s", ts.connStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadConnect(t *testing.T) {
|
||||
checkConnStr(t)
|
||||
SetLogger(testLogger{t})
|
||||
connURL := makeConnStr(t)
|
||||
connURL.User = url.UserPassword("baduser", "badpwd")
|
||||
badDSN := connURL.String()
|
||||
|
||||
conn, err := sql.Open("mssql", badDSN)
|
||||
if err != nil {
|
||||
t.Error("Open connection failed:", err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
err = conn.Ping()
|
||||
if err == nil {
|
||||
t.Error("Ping should fail for connection: ", badDSN)
|
||||
}
|
||||
}
|
||||
123
vendor/github.com/denisenkom/go-mssqldb/types_test.go
generated
vendored
123
vendor/github.com/denisenkom/go-mssqldb/types_test.go
generated
vendored
|
|
@ -1,123 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMakeGoLangScanType(t *testing.T) {
|
||||
if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt8})) {
|
||||
t.Errorf("invalid type returned for typeDateTime")
|
||||
}
|
||||
if (reflect.TypeOf(float64(0)) != makeGoLangScanType(typeInfo{TypeId: typeFlt4})) {
|
||||
t.Errorf("invalid type returned for typeDateTime")
|
||||
}
|
||||
if (reflect.TypeOf(float64(0)) != makeGoLangScanType(typeInfo{TypeId: typeFlt8})) {
|
||||
t.Errorf("invalid type returned for typeDateTime")
|
||||
}
|
||||
if (reflect.TypeOf("") != makeGoLangScanType(typeInfo{TypeId: typeVarChar})) {
|
||||
t.Errorf("invalid type returned for typeDateTime")
|
||||
}
|
||||
if (reflect.TypeOf(time.Time{}) != makeGoLangScanType(typeInfo{TypeId: typeDateTime})) {
|
||||
t.Errorf("invalid type returned for typeDateTime")
|
||||
}
|
||||
if (reflect.TypeOf(time.Time{}) != makeGoLangScanType(typeInfo{TypeId: typeDateTim4})) {
|
||||
t.Errorf("invalid type returned for typeDateTim4")
|
||||
}
|
||||
if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt1})) {
|
||||
t.Errorf("invalid type returned for typeInt1")
|
||||
}
|
||||
if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt2})) {
|
||||
t.Errorf("invalid type returned for typeInt2")
|
||||
}
|
||||
if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt4})) {
|
||||
t.Errorf("invalid type returned for typeInt4")
|
||||
}
|
||||
if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeIntN, Size: 4})) {
|
||||
t.Errorf("invalid type returned for typeIntN")
|
||||
}
|
||||
if (reflect.TypeOf([]byte{}) != makeGoLangScanType(typeInfo{TypeId: typeMoney, Size: 8})) {
|
||||
t.Errorf("invalid type returned for typeIntN")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeGoLangTypeName(t *testing.T) {
|
||||
defer handlePanic(t)
|
||||
|
||||
tests := []struct {
|
||||
typeName string
|
||||
typeString string
|
||||
typeID uint8
|
||||
}{
|
||||
{"typeDateTime", "DATETIME", typeDateTime},
|
||||
{"typeDateTim4", "SMALLDATETIME", typeDateTim4},
|
||||
{"typeBigBinary", "BINARY", typeBigBinary},
|
||||
//TODO: Add other supported types
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if makeGoLangTypeName(typeInfo{TypeId: tt.typeID}) != tt.typeString {
|
||||
t.Errorf("invalid type name returned for %s", tt.typeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeGoLangTypeLength(t *testing.T) {
|
||||
defer handlePanic(t)
|
||||
|
||||
tests := []struct {
|
||||
typeName string
|
||||
typeVarLen bool
|
||||
typeLen int64
|
||||
typeID uint8
|
||||
}{
|
||||
{"typeDateTime", false, 0, typeDateTime},
|
||||
{"typeDateTim4", false, 0, typeDateTim4},
|
||||
{"typeBigBinary", false, 0, typeBigBinary},
|
||||
//TODO: Add other supported types
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
n, v := makeGoLangTypeLength(typeInfo{TypeId: tt.typeID})
|
||||
if v != tt.typeVarLen {
|
||||
t.Errorf("invalid type length variability returned for %s", tt.typeName)
|
||||
}
|
||||
if n != tt.typeLen {
|
||||
t.Errorf("invalid type length returned for %s", tt.typeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeGoLangTypePrecisionScale(t *testing.T) {
|
||||
defer handlePanic(t)
|
||||
|
||||
tests := []struct {
|
||||
typeName string
|
||||
typeID uint8
|
||||
typeVarLen bool
|
||||
typePrec int64
|
||||
typeScale int64
|
||||
}{
|
||||
{"typeDateTime", typeDateTime, false, 0, 0},
|
||||
{"typeDateTim4", typeDateTim4, false, 0, 0},
|
||||
{"typeBigBinary", typeBigBinary, false, 0, 0},
|
||||
//TODO: Add other supported types
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
prec, scale, varLen := makeGoLangTypePrecisionScale(typeInfo{TypeId: tt.typeID})
|
||||
if varLen != tt.typeVarLen {
|
||||
t.Errorf("invalid type length variability returned for %s", tt.typeName)
|
||||
}
|
||||
if prec != tt.typePrec || scale != tt.typeScale {
|
||||
t.Errorf("invalid type precision and/or scale returned for %s", tt.typeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handlePanic(t *testing.T) {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("recovered panic")
|
||||
}
|
||||
}
|
||||
70
vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier_test.go
generated
vendored
70
vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier_test.go
generated
vendored
|
|
@ -1,70 +0,0 @@
|
|||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUniqueIdentifier(t *testing.T) {
|
||||
dbUUID := UniqueIdentifier{0x67, 0x45, 0x23, 0x01,
|
||||
0xAB, 0x89,
|
||||
0xEF, 0xCD,
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
|
||||
}
|
||||
|
||||
uuid := UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
|
||||
|
||||
t.Run("Scan", func(t *testing.T) {
|
||||
t.Run("[]byte", func(t *testing.T) {
|
||||
var sut UniqueIdentifier
|
||||
if err := sut.Scan(dbUUID[:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sut != uuid {
|
||||
t.Errorf("bytes not swapped correctly: got %q; want %q", sut, uuid)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
var sut UniqueIdentifier
|
||||
if err := sut.Scan(uuid.String()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sut != uuid {
|
||||
t.Errorf("string not scanned correctly: got %q; want %q", sut, uuid)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Value", func(t *testing.T) {
|
||||
sut := uuid
|
||||
v, err := sut.Value()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b, ok := v.([]byte)
|
||||
if !ok {
|
||||
t.Fatalf("(%T) is not []byte", v)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, dbUUID[:]) {
|
||||
t.Errorf("got %q; want %q", b, dbUUID)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestUniqueIdentifierString(t *testing.T) {
|
||||
sut := UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
|
||||
expected := "01234567-89AB-CDEF-0123-456789ABCDEF"
|
||||
if actual := sut.String(); actual != expected {
|
||||
t.Errorf("sut.String() = %s; want %s", sut, expected)
|
||||
}
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = UniqueIdentifier{}
|
||||
var _ sql.Scanner = &UniqueIdentifier{}
|
||||
var _ driver.Valuer = UniqueIdentifier{}
|
||||
97
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
97
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
|
|
@ -1,97 +0,0 @@
|
|||
## Migration Guide from v2 -> v3
|
||||
|
||||
Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code.
|
||||
|
||||
### `Token.Claims` is now an interface type
|
||||
|
||||
The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`.
|
||||
|
||||
`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property.
|
||||
|
||||
The old example for parsing a token looked like this..
|
||||
|
||||
```go
|
||||
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
is now directly mapped to...
|
||||
|
||||
```go
|
||||
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type.
|
||||
|
||||
```go
|
||||
type MyCustomClaims struct {
|
||||
User string
|
||||
*StandardClaims
|
||||
}
|
||||
|
||||
if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(*MyCustomClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
|
||||
}
|
||||
```
|
||||
|
||||
### `ParseFromRequest` has been moved
|
||||
|
||||
To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`.
|
||||
|
||||
`Extractors` do the work of picking the token string out of a request. The interface is simple and composable.
|
||||
|
||||
This simple parsing example:
|
||||
|
||||
```go
|
||||
if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
|
||||
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
is directly mapped to:
|
||||
|
||||
```go
|
||||
if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
There are several concrete `Extractor` types provided for your convenience:
|
||||
|
||||
* `HeaderExtractor` will search a list of headers until one contains content.
|
||||
* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
|
||||
* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
|
||||
* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
|
||||
* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
|
||||
* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header
|
||||
|
||||
|
||||
### RSA signing methods no longer accept `[]byte` keys
|
||||
|
||||
Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse.
|
||||
|
||||
To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types.
|
||||
|
||||
```go
|
||||
func keyLookupFunc(*Token) (interface{}, error) {
|
||||
// Don't forget to validate the alg is what you expect:
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
// Look up key
|
||||
key, err := lookupPublicKey(token.Header["kid"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unpack key from PEM encoded PKCS8
|
||||
return jwt.ParseRSAPublicKeyFromPEM(key)
|
||||
}
|
||||
```
|
||||
100
vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
100
vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
|
|
@ -1,100 +0,0 @@
|
|||
# jwt-go
|
||||
|
||||
[](https://travis-ci.org/dgrijalva/jwt-go)
|
||||
[](https://godoc.org/github.com/dgrijalva/jwt-go)
|
||||
|
||||
A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html)
|
||||
|
||||
**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3.
|
||||
|
||||
**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail.
|
||||
|
||||
**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
|
||||
|
||||
## What the heck is a JWT?
|
||||
|
||||
JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
|
||||
|
||||
In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way.
|
||||
|
||||
The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
|
||||
|
||||
The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own.
|
||||
|
||||
## Examples
|
||||
|
||||
See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
|
||||
|
||||
* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
|
||||
* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
|
||||
* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
|
||||
|
||||
## Extensions
|
||||
|
||||
This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.
|
||||
|
||||
Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
|
||||
|
||||
## Compliance
|
||||
|
||||
This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences:
|
||||
|
||||
* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
|
||||
|
||||
## Project Status & Versioning
|
||||
|
||||
This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
|
||||
|
||||
This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases).
|
||||
|
||||
While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning.
|
||||
|
||||
**BREAKING CHANGES:***
|
||||
* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### Signing vs Encryption
|
||||
|
||||
A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
|
||||
|
||||
* The author of the token was in the possession of the signing secret
|
||||
* The data has not been modified since it was signed
|
||||
|
||||
It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library.
|
||||
|
||||
### Choosing a Signing Method
|
||||
|
||||
There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric.
|
||||
|
||||
Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation.
|
||||
|
||||
Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification.
|
||||
|
||||
### Signing Methods and Key Types
|
||||
|
||||
Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
|
||||
|
||||
* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
|
||||
* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
|
||||
* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
|
||||
|
||||
### JWT and OAuth
|
||||
|
||||
It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication.
|
||||
|
||||
Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
|
||||
|
||||
* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
|
||||
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
||||
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
||||
|
||||
## More
|
||||
|
||||
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
|
||||
|
||||
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
|
||||
118
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
118
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
|
|
@ -1,118 +0,0 @@
|
|||
## `jwt-go` Version History
|
||||
|
||||
#### 3.2.0
|
||||
|
||||
* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
|
||||
* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
|
||||
* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
|
||||
* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
|
||||
|
||||
#### 3.1.0
|
||||
|
||||
* Improvements to `jwt` command line tool
|
||||
* Added `SkipClaimsValidation` option to `Parser`
|
||||
* Documentation updates
|
||||
|
||||
#### 3.0.0
|
||||
|
||||
* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
|
||||
* Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
|
||||
* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
|
||||
* The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims.
|
||||
* Other Additions and Changes
|
||||
* Added `Claims` interface type to allow users to decode the claims into a custom type
|
||||
* Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into.
|
||||
* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
|
||||
* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
|
||||
* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
|
||||
* Added several new, more specific, validation errors to error type bitmask
|
||||
* Moved examples from README to executable example files
|
||||
* Signing method registry is now thread safe
|
||||
* Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
|
||||
|
||||
#### 2.7.0
|
||||
|
||||
This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
|
||||
|
||||
* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
|
||||
* Error text for expired tokens includes how long it's been expired
|
||||
* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
|
||||
* Documentation updates
|
||||
|
||||
#### 2.6.0
|
||||
|
||||
* Exposed inner error within ValidationError
|
||||
* Fixed validation errors when using UseJSONNumber flag
|
||||
* Added several unit tests
|
||||
|
||||
#### 2.5.0
|
||||
|
||||
* Added support for signing method none. You shouldn't use this. The API tries to make this clear.
|
||||
* Updated/fixed some documentation
|
||||
* Added more helpful error message when trying to parse tokens that begin with `BEARER `
|
||||
|
||||
#### 2.4.0
|
||||
|
||||
* Added new type, Parser, to allow for configuration of various parsing parameters
|
||||
* You can now specify a list of valid signing methods. Anything outside this set will be rejected.
|
||||
* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
|
||||
* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
|
||||
* Fixed some bugs with ECDSA parsing
|
||||
|
||||
#### 2.3.0
|
||||
|
||||
* Added support for ECDSA signing methods
|
||||
* Added support for RSA PSS signing methods (requires go v1.4)
|
||||
|
||||
#### 2.2.0
|
||||
|
||||
* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic.
|
||||
|
||||
#### 2.1.0
|
||||
|
||||
Backwards compatible API change that was missed in 2.0.0.
|
||||
|
||||
* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
|
||||
|
||||
#### 2.0.0
|
||||
|
||||
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
|
||||
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
|
||||
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
|
||||
|
||||
* **Compatibility Breaking Changes**
|
||||
* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
|
||||
* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
|
||||
* `KeyFunc` now returns `interface{}` instead of `[]byte`
|
||||
* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
|
||||
* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
|
||||
* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type.
|
||||
* Added public package global `SigningMethodHS256`
|
||||
* Added public package global `SigningMethodHS384`
|
||||
* Added public package global `SigningMethodHS512`
|
||||
* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type.
|
||||
* Added public package global `SigningMethodRS256`
|
||||
* Added public package global `SigningMethodRS384`
|
||||
* Added public package global `SigningMethodRS512`
|
||||
* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged.
|
||||
* Refactored the RSA implementation to be easier to read
|
||||
* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
|
||||
|
||||
#### 1.0.2
|
||||
|
||||
* Fixed bug in parsing public keys from certificates
|
||||
* Added more tests around the parsing of keys for RS256
|
||||
* Code refactoring in RS256 implementation. No functional changes
|
||||
|
||||
#### 1.0.1
|
||||
|
||||
* Fixed panic if RS256 signing method was passed an invalid key
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
* First versioned release
|
||||
* API stabilized
|
||||
* Supports creating, signing, parsing, and validating JWT tokens
|
||||
* Supports RS256 and HS256 signing methods
|
||||
100
vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go
generated
vendored
100
vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go
generated
vendored
|
|
@ -1,100 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
var ecdsaTestData = []struct {
|
||||
name string
|
||||
keys map[string]string
|
||||
tokenString string
|
||||
alg string
|
||||
claims map[string]interface{}
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
"Basic ES256",
|
||||
map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmb28iOiJiYXIifQ.feG39E-bn8HXAKhzDZq7yEAPWYDhZlwTn3sePJnU9VrGMmwdXAIEyoOnrjreYlVM_Z4N13eK9-TmMTWyfKJtHQ",
|
||||
"ES256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic ES384",
|
||||
map[string]string{"private": "test/ec384-private.pem", "public": "test/ec384-public.pem"},
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJmb28iOiJiYXIifQ.ngAfKMbJUh0WWubSIYe5GMsA-aHNKwFbJk_wq3lq23aPp8H2anb1rRILIzVR0gUf4a8WzDtrzmiikuPWyCS6CN4-PwdgTk-5nehC7JXqlaBZU05p3toM3nWCwm_LXcld",
|
||||
"ES384",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic ES512",
|
||||
map[string]string{"private": "test/ec512-private.pem", "public": "test/ec512-public.pem"},
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJmb28iOiJiYXIifQ.AAU0TvGQOcdg2OvrwY73NHKgfk26UDekh9Prz-L_iWuTBIBqOFCWwwLsRiHB1JOddfKAls5do1W0jR_F30JpVd-6AJeTjGKA4C1A1H6gIKwRY0o_tFDIydZCl_lMBMeG5VNFAjO86-WCSKwc3hqaGkq1MugPRq_qrF9AVbuEB4JPLyL5",
|
||||
"ES512",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"basic ES256 invalid: foo => bar",
|
||||
map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
|
||||
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MEQCIHoSJnmGlPaVQDqacx_2XlXEhhqtWceVopjomc2PJLtdAiAUTeGPoNYxZw0z8mgOnnIcjoxRuNDVZvybRZF3wR1l8W",
|
||||
"ES256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestECDSAVerify(t *testing.T) {
|
||||
for _, data := range ecdsaTestData {
|
||||
var err error
|
||||
|
||||
key, _ := ioutil.ReadFile(data.keys["public"])
|
||||
|
||||
var ecdsaKey *ecdsa.PublicKey
|
||||
if ecdsaKey, err = jwt.ParseECPublicKeyFromPEM(key); err != nil {
|
||||
t.Errorf("Unable to parse ECDSA public key: %v", err)
|
||||
}
|
||||
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ecdsaKey)
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
||||
}
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestECDSASign(t *testing.T) {
|
||||
for _, data := range ecdsaTestData {
|
||||
var err error
|
||||
key, _ := ioutil.ReadFile(data.keys["private"])
|
||||
|
||||
var ecdsaKey *ecdsa.PrivateKey
|
||||
if ecdsaKey, err = jwt.ParseECPrivateKeyFromPEM(key); err != nil {
|
||||
t.Errorf("Unable to parse ECDSA private key: %v", err)
|
||||
}
|
||||
|
||||
if data.valid {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), ecdsaKey)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
||||
}
|
||||
if sig == parts[2] {
|
||||
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
vendor/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
114
vendor/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
|
|
@ -1,114 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Example (atypical) using the StandardClaims type by itself to parse a token.
|
||||
// The StandardClaims type is designed to be embedded into your custom types
|
||||
// to provide standard validation features. You can use it alone, but there's
|
||||
// no way to retrieve other fields after parsing.
|
||||
// See the CustomClaimsType example for intended usage.
|
||||
func ExampleNewWithClaims_standardClaims() {
|
||||
mySigningKey := []byte("AllYourBase")
|
||||
|
||||
// Create the Claims
|
||||
claims := &jwt.StandardClaims{
|
||||
ExpiresAt: 15000,
|
||||
Issuer: "test",
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
ss, err := token.SignedString(mySigningKey)
|
||||
fmt.Printf("%v %v", ss, err)
|
||||
//Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.QsODzZu3lUZMVdhbO76u3Jv02iYCvEHcYVUI1kOWEU0 <nil>
|
||||
}
|
||||
|
||||
// Example creating a token using a custom claims type. The StandardClaim is embedded
|
||||
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
|
||||
func ExampleNewWithClaims_customClaimsType() {
|
||||
mySigningKey := []byte("AllYourBase")
|
||||
|
||||
type MyCustomClaims struct {
|
||||
Foo string `json:"foo"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
// Create the Claims
|
||||
claims := MyCustomClaims{
|
||||
"bar",
|
||||
jwt.StandardClaims{
|
||||
ExpiresAt: 15000,
|
||||
Issuer: "test",
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
ss, err := token.SignedString(mySigningKey)
|
||||
fmt.Printf("%v %v", ss, err)
|
||||
//Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c <nil>
|
||||
}
|
||||
|
||||
// Example creating a token using a custom claims type. The StandardClaim is embedded
|
||||
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
|
||||
func ExampleParseWithClaims_customClaimsType() {
|
||||
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
|
||||
|
||||
type MyCustomClaims struct {
|
||||
Foo string `json:"foo"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
// sample token is expired. override time so it parses as valid
|
||||
at(time.Unix(0, 0), func() {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte("AllYourBase"), nil
|
||||
})
|
||||
|
||||
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
|
||||
fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
})
|
||||
|
||||
// Output: bar 15000
|
||||
}
|
||||
|
||||
// Override time value for tests. Restore default value after.
|
||||
func at(t time.Time, f func()) {
|
||||
jwt.TimeFunc = func() time.Time {
|
||||
return t
|
||||
}
|
||||
f()
|
||||
jwt.TimeFunc = time.Now
|
||||
}
|
||||
|
||||
// An example of parsing the error types using bitfield checks
|
||||
func ExampleParse_errorChecking() {
|
||||
// Token from another example. This token is expired
|
||||
var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
|
||||
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte("AllYourBase"), nil
|
||||
})
|
||||
|
||||
if token.Valid {
|
||||
fmt.Println("You look nice today")
|
||||
} else if ve, ok := err.(*jwt.ValidationError); ok {
|
||||
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
|
||||
fmt.Println("That's not even a token")
|
||||
} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
|
||||
// Token is either expired or not active yet
|
||||
fmt.Println("Timing is everything")
|
||||
} else {
|
||||
fmt.Println("Couldn't handle this token:", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Couldn't handle this token:", err)
|
||||
}
|
||||
|
||||
// Output: Timing is everything
|
||||
}
|
||||
66
vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go
generated
vendored
66
vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go
generated
vendored
|
|
@ -1,66 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
)
|
||||
|
||||
// For HMAC signing method, the key can be any []byte. It is recommended to generate
|
||||
// a key using crypto/rand or something equivalent. You need the same key for signing
|
||||
// and validating.
|
||||
var hmacSampleSecret []byte
|
||||
|
||||
func init() {
|
||||
// Load sample key data
|
||||
if keyData, e := ioutil.ReadFile("test/hmacTestKey"); e == nil {
|
||||
hmacSampleSecret = keyData
|
||||
} else {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Example creating, signing, and encoding a JWT token using the HMAC signing method
|
||||
func ExampleNew_hmac() {
|
||||
// Create a new token object, specifying signing method and the claims
|
||||
// you would like it to contain.
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"foo": "bar",
|
||||
"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
|
||||
})
|
||||
|
||||
// Sign and get the complete encoded token as a string using the secret
|
||||
tokenString, err := token.SignedString(hmacSampleSecret)
|
||||
|
||||
fmt.Println(tokenString, err)
|
||||
// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU <nil>
|
||||
}
|
||||
|
||||
// Example parsing and validating a token using the HMAC signing method
|
||||
func ExampleParse_hmac() {
|
||||
// sample token string taken from the New example
|
||||
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU"
|
||||
|
||||
// Parse takes the token string and a function for looking up the key. The latter is especially
|
||||
// useful if you use multiple keys for your application. The standard is to use 'kid' in the
|
||||
// head of the token to identify which key to use, but the parsed token (head and claims) is provided
|
||||
// to the callback, providing flexibility.
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
// Don't forget to validate the alg is what you expect:
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
||||
return hmacSampleSecret, nil
|
||||
})
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
fmt.Println(claims["foo"], claims["nbf"])
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Output: bar 1.4444784e+09
|
||||
}
|
||||
91
vendor/github.com/dgrijalva/jwt-go/hmac_test.go
generated
vendored
91
vendor/github.com/dgrijalva/jwt-go/hmac_test.go
generated
vendored
|
|
@ -1,91 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var hmacTestData = []struct {
|
||||
name string
|
||||
tokenString string
|
||||
alg string
|
||||
claims map[string]interface{}
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
"web sample",
|
||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
|
||||
"HS256",
|
||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"HS384",
|
||||
"eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.KWZEuOD5lbBxZ34g7F-SlVLAQ_r5KApWNWlZIIMyQVz5Zs58a7XdNzj5_0EcNoOy",
|
||||
"HS384",
|
||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"HS512",
|
||||
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.CN7YijRX6Aw1n2jyI2Id1w90ja-DEMYiWixhYCyHnrZ1VfJRaFQz1bEbjjA5Fn4CLYaUG432dEYmSbS4Saokmw",
|
||||
"HS512",
|
||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"web sample: invalid",
|
||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXo",
|
||||
"HS256",
|
||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
// Sample data from http://tools.ietf.org/html/draft-jones-json-web-signature-04#appendix-A.1
|
||||
var hmacTestKey, _ = ioutil.ReadFile("test/hmacTestKey")
|
||||
|
||||
func TestHMACVerify(t *testing.T) {
|
||||
for _, data := range hmacTestData {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], hmacTestKey)
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
||||
}
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHMACSign(t *testing.T) {
|
||||
for _, data := range hmacTestData {
|
||||
if data.valid {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), hmacTestKey)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
||||
}
|
||||
if sig != parts[2] {
|
||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHS256Signing(b *testing.B) {
|
||||
benchmarkSigning(b, jwt.SigningMethodHS256, hmacTestKey)
|
||||
}
|
||||
|
||||
func BenchmarkHS384Signing(b *testing.B) {
|
||||
benchmarkSigning(b, jwt.SigningMethodHS384, hmacTestKey)
|
||||
}
|
||||
|
||||
func BenchmarkHS512Signing(b *testing.B) {
|
||||
benchmarkSigning(b, jwt.SigningMethodHS512, hmacTestKey)
|
||||
}
|
||||
216
vendor/github.com/dgrijalva/jwt-go/http_example_test.go
generated
vendored
216
vendor/github.com/dgrijalva/jwt-go/http_example_test.go
generated
vendored
|
|
@ -1,216 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
// Example HTTP auth using asymmetric crypto/RSA keys
|
||||
// This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/request"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// location of the files used for signing and verification
|
||||
const (
|
||||
privKeyPath = "test/sample_key" // openssl genrsa -out app.rsa keysize
|
||||
pubKeyPath = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
|
||||
)
|
||||
|
||||
var (
|
||||
verifyKey *rsa.PublicKey
|
||||
signKey *rsa.PrivateKey
|
||||
serverPort int
|
||||
// storing sample username/password pairs
|
||||
// don't do this on a real server
|
||||
users = map[string]string{
|
||||
"test": "known",
|
||||
}
|
||||
)
|
||||
|
||||
// read the key files before starting http handlers
|
||||
func init() {
|
||||
signBytes, err := ioutil.ReadFile(privKeyPath)
|
||||
fatal(err)
|
||||
|
||||
signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
|
||||
fatal(err)
|
||||
|
||||
verifyBytes, err := ioutil.ReadFile(pubKeyPath)
|
||||
fatal(err)
|
||||
|
||||
verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
|
||||
fatal(err)
|
||||
|
||||
http.HandleFunc("/authenticate", authHandler)
|
||||
http.HandleFunc("/restricted", restrictedHandler)
|
||||
|
||||
// Setup listener
|
||||
listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
|
||||
serverPort = listener.Addr().(*net.TCPAddr).Port
|
||||
|
||||
log.Println("Listening...")
|
||||
go func() {
|
||||
fatal(http.Serve(listener, nil))
|
||||
}()
|
||||
}
|
||||
|
||||
var start func()
|
||||
|
||||
func fatal(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Define some custom types were going to use within our tokens
|
||||
type CustomerInfo struct {
|
||||
Name string
|
||||
Kind string
|
||||
}
|
||||
|
||||
type CustomClaimsExample struct {
|
||||
*jwt.StandardClaims
|
||||
TokenType string
|
||||
CustomerInfo
|
||||
}
|
||||
|
||||
func Example_getTokenViaHTTP() {
|
||||
// See func authHandler for an example auth handler that produces a token
|
||||
res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
|
||||
"user": {"test"},
|
||||
"pass": {"known"},
|
||||
})
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
fmt.Println("Unexpected status code", res.StatusCode)
|
||||
}
|
||||
|
||||
// Read the token out of the response body
|
||||
buf := new(bytes.Buffer)
|
||||
io.Copy(buf, res.Body)
|
||||
res.Body.Close()
|
||||
tokenString := strings.TrimSpace(buf.String())
|
||||
|
||||
// Parse the token
|
||||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
|
||||
// since we only use the one private key to sign the tokens,
|
||||
// we also only use its public counter part to verify
|
||||
return verifyKey, nil
|
||||
})
|
||||
fatal(err)
|
||||
|
||||
claims := token.Claims.(*CustomClaimsExample)
|
||||
fmt.Println(claims.CustomerInfo.Name)
|
||||
|
||||
//Output: test
|
||||
}
|
||||
|
||||
func Example_useTokenViaHTTP() {
|
||||
|
||||
// Make a sample token
|
||||
// In a real world situation, this token will have been acquired from
|
||||
// some other API call (see Example_getTokenViaHTTP)
|
||||
token, err := createToken("foo")
|
||||
fatal(err)
|
||||
|
||||
// Make request. See func restrictedHandler for example request processor
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
|
||||
fatal(err)
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
fatal(err)
|
||||
|
||||
// Read the response body
|
||||
buf := new(bytes.Buffer)
|
||||
io.Copy(buf, res.Body)
|
||||
res.Body.Close()
|
||||
fmt.Println(buf.String())
|
||||
|
||||
// Output: Welcome, foo
|
||||
}
|
||||
|
||||
func createToken(user string) (string, error) {
|
||||
// create a signer for rsa 256
|
||||
t := jwt.New(jwt.GetSigningMethod("RS256"))
|
||||
|
||||
// set our claims
|
||||
t.Claims = &CustomClaimsExample{
|
||||
&jwt.StandardClaims{
|
||||
// set the expire time
|
||||
// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
|
||||
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
|
||||
},
|
||||
"level1",
|
||||
CustomerInfo{user, "human"},
|
||||
}
|
||||
|
||||
// Creat token string
|
||||
return t.SignedString(signKey)
|
||||
}
|
||||
|
||||
// reads the form values, checks them and creates the token
|
||||
func authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// make sure its post
|
||||
if r.Method != "POST" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "No POST", r.Method)
|
||||
return
|
||||
}
|
||||
|
||||
user := r.FormValue("user")
|
||||
pass := r.FormValue("pass")
|
||||
|
||||
log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)
|
||||
|
||||
// check values
|
||||
if user != "test" || pass != "known" {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
fmt.Fprintln(w, "Wrong info")
|
||||
return
|
||||
}
|
||||
|
||||
tokenString, err := createToken(user)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintln(w, "Sorry, error while Signing Token!")
|
||||
log.Printf("Token Signing error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/jwt")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintln(w, tokenString)
|
||||
}
|
||||
|
||||
// only accessible with a valid token
|
||||
func restrictedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Get token from request
|
||||
token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
|
||||
// since we only use the one private key to sign the tokens,
|
||||
// we also only use its public counter part to verify
|
||||
return verifyKey, nil
|
||||
})
|
||||
|
||||
// If the token is missing or invalid, return error
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
fmt.Fprintln(w, "Invalid token:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Token is valid
|
||||
fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
|
||||
return
|
||||
}
|
||||
72
vendor/github.com/dgrijalva/jwt-go/none_test.go
generated
vendored
72
vendor/github.com/dgrijalva/jwt-go/none_test.go
generated
vendored
|
|
@ -1,72 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var noneTestData = []struct {
|
||||
name string
|
||||
tokenString string
|
||||
alg string
|
||||
key interface{}
|
||||
claims map[string]interface{}
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
"Basic",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
|
||||
"none",
|
||||
jwt.UnsafeAllowNoneSignatureType,
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic - no key",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
|
||||
"none",
|
||||
nil,
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Signed",
|
||||
"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
|
||||
"none",
|
||||
jwt.UnsafeAllowNoneSignatureType,
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestNoneVerify(t *testing.T) {
|
||||
for _, data := range noneTestData {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], data.key)
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
||||
}
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoneSign(t *testing.T) {
|
||||
for _, data := range noneTestData {
|
||||
if data.valid {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), data.key)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
||||
}
|
||||
if sig != parts[2] {
|
||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
301
vendor/github.com/dgrijalva/jwt-go/parser_test.go
generated
vendored
301
vendor/github.com/dgrijalva/jwt-go/parser_test.go
generated
vendored
|
|
@ -1,301 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/test"
|
||||
)
|
||||
|
||||
var keyFuncError error = fmt.Errorf("error loading key")
|
||||
|
||||
var (
|
||||
jwtTestDefaultKey *rsa.PublicKey
|
||||
defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
|
||||
emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
|
||||
errorKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, keyFuncError }
|
||||
nilKeyFunc jwt.Keyfunc = nil
|
||||
)
|
||||
|
||||
func init() {
|
||||
jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
|
||||
}
|
||||
|
||||
var jwtTestData = []struct {
|
||||
name string
|
||||
tokenString string
|
||||
keyfunc jwt.Keyfunc
|
||||
claims jwt.Claims
|
||||
valid bool
|
||||
errors uint32
|
||||
parser *jwt.Parser
|
||||
}{
|
||||
{
|
||||
"basic",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
true,
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic expired",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
|
||||
false,
|
||||
jwt.ValidationErrorExpired,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic nbf",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
|
||||
false,
|
||||
jwt.ValidationErrorNotValidYet,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"expired and nbf",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
|
||||
false,
|
||||
jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic invalid",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
false,
|
||||
jwt.ValidationErrorSignatureInvalid,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic nokeyfunc",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
nilKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
false,
|
||||
jwt.ValidationErrorUnverifiable,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic nokey",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
emptyKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
false,
|
||||
jwt.ValidationErrorSignatureInvalid,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"basic errorkey",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
errorKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
false,
|
||||
jwt.ValidationErrorUnverifiable,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid signing method",
|
||||
"",
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
false,
|
||||
jwt.ValidationErrorSignatureInvalid,
|
||||
&jwt.Parser{ValidMethods: []string{"HS256"}},
|
||||
},
|
||||
{
|
||||
"valid signing method",
|
||||
"",
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar"},
|
||||
true,
|
||||
0,
|
||||
&jwt.Parser{ValidMethods: []string{"RS256", "HS256"}},
|
||||
},
|
||||
{
|
||||
"JSON Number",
|
||||
"",
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": json.Number("123.4")},
|
||||
true,
|
||||
0,
|
||||
&jwt.Parser{UseJSONNumber: true},
|
||||
},
|
||||
{
|
||||
"Standard Claims",
|
||||
"",
|
||||
defaultKeyFunc,
|
||||
&jwt.StandardClaims{
|
||||
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
||||
},
|
||||
true,
|
||||
0,
|
||||
&jwt.Parser{UseJSONNumber: true},
|
||||
},
|
||||
{
|
||||
"JSON Number - basic expired",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
||||
false,
|
||||
jwt.ValidationErrorExpired,
|
||||
&jwt.Parser{UseJSONNumber: true},
|
||||
},
|
||||
{
|
||||
"JSON Number - basic nbf",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
||||
false,
|
||||
jwt.ValidationErrorNotValidYet,
|
||||
&jwt.Parser{UseJSONNumber: true},
|
||||
},
|
||||
{
|
||||
"JSON Number - expired and nbf",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
||||
false,
|
||||
jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
|
||||
&jwt.Parser{UseJSONNumber: true},
|
||||
},
|
||||
{
|
||||
"SkipClaimsValidation during token parsing",
|
||||
"", // autogen
|
||||
defaultKeyFunc,
|
||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
||||
true,
|
||||
0,
|
||||
&jwt.Parser{UseJSONNumber: true, SkipClaimsValidation: true},
|
||||
},
|
||||
}
|
||||
|
||||
func TestParser_Parse(t *testing.T) {
|
||||
privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
|
||||
|
||||
// Iterate over test data set and run tests
|
||||
for _, data := range jwtTestData {
|
||||
// If the token string is blank, use helper function to generate string
|
||||
if data.tokenString == "" {
|
||||
data.tokenString = test.MakeSampleToken(data.claims, privateKey)
|
||||
}
|
||||
|
||||
// Parse the token
|
||||
var token *jwt.Token
|
||||
var err error
|
||||
var parser = data.parser
|
||||
if parser == nil {
|
||||
parser = new(jwt.Parser)
|
||||
}
|
||||
// Figure out correct claims type
|
||||
switch data.claims.(type) {
|
||||
case jwt.MapClaims:
|
||||
token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
|
||||
case *jwt.StandardClaims:
|
||||
token, err = parser.ParseWithClaims(data.tokenString, &jwt.StandardClaims{}, data.keyfunc)
|
||||
}
|
||||
|
||||
// Verify result matches expectation
|
||||
if !reflect.DeepEqual(data.claims, token.Claims) {
|
||||
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
||||
}
|
||||
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
|
||||
}
|
||||
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid token passed validation", data.name)
|
||||
}
|
||||
|
||||
if (err == nil && !token.Valid) || (err != nil && token.Valid) {
|
||||
t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
|
||||
}
|
||||
|
||||
if data.errors != 0 {
|
||||
if err == nil {
|
||||
t.Errorf("[%v] Expecting error. Didn't get one.", data.name)
|
||||
} else {
|
||||
|
||||
ve := err.(*jwt.ValidationError)
|
||||
// compare the bitfield part of the error
|
||||
if e := ve.Errors; e != data.errors {
|
||||
t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors)
|
||||
}
|
||||
|
||||
if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError {
|
||||
t.Errorf("[%v] Inner error does not match expectation. %v != %v", data.name, ve.Inner, keyFuncError)
|
||||
}
|
||||
}
|
||||
}
|
||||
if data.valid && token.Signature == "" {
|
||||
t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseUnverified(t *testing.T) {
|
||||
privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
|
||||
|
||||
// Iterate over test data set and run tests
|
||||
for _, data := range jwtTestData {
|
||||
// If the token string is blank, use helper function to generate string
|
||||
if data.tokenString == "" {
|
||||
data.tokenString = test.MakeSampleToken(data.claims, privateKey)
|
||||
}
|
||||
|
||||
// Parse the token
|
||||
var token *jwt.Token
|
||||
var err error
|
||||
var parser = data.parser
|
||||
if parser == nil {
|
||||
parser = new(jwt.Parser)
|
||||
}
|
||||
// Figure out correct claims type
|
||||
switch data.claims.(type) {
|
||||
case jwt.MapClaims:
|
||||
token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{})
|
||||
case *jwt.StandardClaims:
|
||||
token, _, err = parser.ParseUnverified(data.tokenString, &jwt.StandardClaims{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Invalid token", data.name)
|
||||
}
|
||||
|
||||
// Verify result matches expectation
|
||||
if !reflect.DeepEqual(data.claims, token.Claims) {
|
||||
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
||||
}
|
||||
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method for benchmarking various methods
|
||||
func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) {
|
||||
t := jwt.New(method)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
if _, err := t.SignedString(key); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
96
vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go
generated
vendored
96
vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go
generated
vendored
|
|
@ -1,96 +0,0 @@
|
|||
// +build go1.4
|
||||
|
||||
package jwt_test
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
var rsaPSSTestData = []struct {
|
||||
name string
|
||||
tokenString string
|
||||
alg string
|
||||
claims map[string]interface{}
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
"Basic PS256",
|
||||
"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9w",
|
||||
"PS256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic PS384",
|
||||
"eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.w7-qqgj97gK4fJsq_DCqdYQiylJjzWONvD0qWWWhqEOFk2P1eDULPnqHRnjgTXoO4HAw4YIWCsZPet7nR3Xxq4ZhMqvKW8b7KlfRTb9cH8zqFvzMmybQ4jv2hKc3bXYqVow3AoR7hN_CWXI3Dv6Kd2X5xhtxRHI6IL39oTVDUQ74LACe-9t4c3QRPuj6Pq1H4FAT2E2kW_0KOc6EQhCLWEhm2Z2__OZskDC8AiPpP8Kv4k2vB7l0IKQu8Pr4RcNBlqJdq8dA5D3hk5TLxP8V5nG1Ib80MOMMqoS3FQvSLyolFX-R_jZ3-zfq6Ebsqr0yEb0AH2CfsECF7935Pa0FKQ",
|
||||
"PS384",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic PS512",
|
||||
"eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.GX1HWGzFaJevuSLavqqFYaW8_TpvcjQ8KfC5fXiSDzSiT9UD9nB_ikSmDNyDILNdtjZLSvVKfXxZJqCfefxAtiozEDDdJthZ-F0uO4SPFHlGiXszvKeodh7BuTWRI2wL9-ZO4mFa8nq3GMeQAfo9cx11i7nfN8n2YNQ9SHGovG7_T_AvaMZB_jT6jkDHpwGR9mz7x1sycckEo6teLdHRnH_ZdlHlxqknmyTu8Odr5Xh0sJFOL8BepWbbvIIn-P161rRHHiDWFv6nhlHwZnVzjx7HQrWSGb6-s2cdLie9QL_8XaMcUpjLkfOMKkDOfHo6AvpL7Jbwi83Z2ZTHjJWB-A",
|
||||
"PS512",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"basic PS256 invalid: foo => bar",
|
||||
"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9W",
|
||||
"PS256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestRSAPSSVerify(t *testing.T) {
|
||||
var err error
|
||||
|
||||
key, _ := ioutil.ReadFile("test/sample_key.pub")
|
||||
var rsaPSSKey *rsa.PublicKey
|
||||
if rsaPSSKey, err = jwt.ParseRSAPublicKeyFromPEM(key); err != nil {
|
||||
t.Errorf("Unable to parse RSA public key: %v", err)
|
||||
}
|
||||
|
||||
for _, data := range rsaPSSTestData {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], rsaPSSKey)
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
||||
}
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAPSSSign(t *testing.T) {
|
||||
var err error
|
||||
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
var rsaPSSKey *rsa.PrivateKey
|
||||
if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
|
||||
t.Errorf("Unable to parse RSA private key: %v", err)
|
||||
}
|
||||
|
||||
for _, data := range rsaPSSTestData {
|
||||
if data.valid {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), rsaPSSKey)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
||||
}
|
||||
if sig == parts[2] {
|
||||
t.Errorf("[%v] Signatures shouldn't match\nnew:\n%v\noriginal:\n%v", data.name, sig, parts[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
185
vendor/github.com/dgrijalva/jwt-go/rsa_test.go
generated
vendored
185
vendor/github.com/dgrijalva/jwt-go/rsa_test.go
generated
vendored
|
|
@ -1,185 +0,0 @@
|
|||
package jwt_test
|
||||
|
||||
import (
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var rsaTestData = []struct {
|
||||
name string
|
||||
tokenString string
|
||||
alg string
|
||||
claims map[string]interface{}
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
"Basic RS256",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
"RS256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic RS384",
|
||||
"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
|
||||
"RS384",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Basic RS512",
|
||||
"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.zBlLlmRrUxx4SJPUbV37Q1joRcI9EW13grnKduK3wtYKmDXbgDpF1cZ6B-2Jsm5RB8REmMiLpGms-EjXhgnyh2TSHE-9W2gA_jvshegLWtwRVDX40ODSkTb7OVuaWgiy9y7llvcknFBTIg-FnVPVpXMmeV_pvwQyhaz1SSwSPrDyxEmksz1hq7YONXhXPpGaNbMMeDTNP_1oj8DZaqTIL9TwV8_1wb2Odt_Fy58Ke2RVFijsOLdnyEAjt2n9Mxihu9i3PhNBkkxa2GbnXBfq3kzvZ_xxGGopLdHhJjcGWXO-NiwI9_tiu14NRv4L2xC0ItD9Yz68v2ZIZEp_DuzwRQ",
|
||||
"RS512",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"basic invalid: foo => bar",
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
||||
"RS256",
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestRSAVerify(t *testing.T) {
|
||||
keyData, _ := ioutil.ReadFile("test/sample_key.pub")
|
||||
key, _ := jwt.ParseRSAPublicKeyFromPEM(keyData)
|
||||
|
||||
for _, data := range rsaTestData {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], key)
|
||||
if data.valid && err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
||||
}
|
||||
if !data.valid && err == nil {
|
||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSASign(t *testing.T) {
|
||||
keyData, _ := ioutil.ReadFile("test/sample_key")
|
||||
key, _ := jwt.ParseRSAPrivateKeyFromPEM(keyData)
|
||||
|
||||
for _, data := range rsaTestData {
|
||||
if data.valid {
|
||||
parts := strings.Split(data.tokenString, ".")
|
||||
method := jwt.GetSigningMethod(data.alg)
|
||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), key)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
||||
}
|
||||
if sig != parts[2] {
|
||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAVerifyWithPreParsedPrivateKey(t *testing.T) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key.pub")
|
||||
parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testData := rsaTestData[0]
|
||||
parts := strings.Split(testData.tokenString, ".")
|
||||
err = jwt.SigningMethodRS256.Verify(strings.Join(parts[0:2], "."), parts[2], parsedKey)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error while verifying key: %v", testData.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAWithPreParsedPrivateKey(t *testing.T) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testData := rsaTestData[0]
|
||||
parts := strings.Split(testData.tokenString, ".")
|
||||
sig, err := jwt.SigningMethodRS256.Sign(strings.Join(parts[0:2], "."), parsedKey)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] Error signing token: %v", testData.name, err)
|
||||
}
|
||||
if sig != parts[2] {
|
||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", testData.name, sig, parts[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAKeyParsing(t *testing.T) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
secureKey, _ := ioutil.ReadFile("test/privateSecure.pem")
|
||||
pubKey, _ := ioutil.ReadFile("test/sample_key.pub")
|
||||
badKey := []byte("All your base are belong to key")
|
||||
|
||||
// Test parsePrivateKey
|
||||
if _, e := jwt.ParseRSAPrivateKeyFromPEM(key); e != nil {
|
||||
t.Errorf("Failed to parse valid private key: %v", e)
|
||||
}
|
||||
|
||||
if k, e := jwt.ParseRSAPrivateKeyFromPEM(pubKey); e == nil {
|
||||
t.Errorf("Parsed public key as valid private key: %v", k)
|
||||
}
|
||||
|
||||
if k, e := jwt.ParseRSAPrivateKeyFromPEM(badKey); e == nil {
|
||||
t.Errorf("Parsed invalid key as valid private key: %v", k)
|
||||
}
|
||||
|
||||
if _, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "password"); e != nil {
|
||||
t.Errorf("Failed to parse valid private key with password: %v", e)
|
||||
}
|
||||
|
||||
if k, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "123132"); e == nil {
|
||||
t.Errorf("Parsed private key with invalid password %v", k)
|
||||
}
|
||||
|
||||
// Test parsePublicKey
|
||||
if _, e := jwt.ParseRSAPublicKeyFromPEM(pubKey); e != nil {
|
||||
t.Errorf("Failed to parse valid public key: %v", e)
|
||||
}
|
||||
|
||||
if k, e := jwt.ParseRSAPublicKeyFromPEM(key); e == nil {
|
||||
t.Errorf("Parsed private key as valid public key: %v", k)
|
||||
}
|
||||
|
||||
if k, e := jwt.ParseRSAPublicKeyFromPEM(badKey); e == nil {
|
||||
t.Errorf("Parsed invalid key as valid private key: %v", k)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkRS256Signing(b *testing.B) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
benchmarkSigning(b, jwt.SigningMethodRS256, parsedKey)
|
||||
}
|
||||
|
||||
func BenchmarkRS384Signing(b *testing.B) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
benchmarkSigning(b, jwt.SigningMethodRS384, parsedKey)
|
||||
}
|
||||
|
||||
func BenchmarkRS512Signing(b *testing.B) {
|
||||
key, _ := ioutil.ReadFile("test/sample_key")
|
||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
benchmarkSigning(b, jwt.SigningMethodRS512, parsedKey)
|
||||
}
|
||||
178
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
178
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
|
|
@ -1,178 +0,0 @@
|
|||
## Version 1.4.1 (2018-11-14)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fix TIME format for binary columns (#818)
|
||||
- Fix handling of empty auth plugin names (#835)
|
||||
- Fix caching_sha2_password with empty password (#826)
|
||||
- Fix canceled context broke mysqlConn (#862)
|
||||
- Fix OldAuthSwitchRequest support (#870)
|
||||
- Fix Auth Response packet for cleartext password (#887)
|
||||
|
||||
## Version 1.4 (2018-06-03)
|
||||
|
||||
Changes:
|
||||
|
||||
- Documentation fixes (#530, #535, #567)
|
||||
- Refactoring (#575, #579, #580, #581, #603, #615, #704)
|
||||
- Cache column names (#444)
|
||||
- Sort the DSN parameters in DSNs generated from a config (#637)
|
||||
- Allow native password authentication by default (#644)
|
||||
- Use the default port if it is missing in the DSN (#668)
|
||||
- Removed the `strict` mode (#676)
|
||||
- Do not query `max_allowed_packet` by default (#680)
|
||||
- Dropped support Go 1.6 and lower (#696)
|
||||
- Updated `ConvertValue()` to match the database/sql/driver implementation (#760)
|
||||
- Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783)
|
||||
- Improved the compatibility of the authentication system (#807)
|
||||
|
||||
New Features:
|
||||
|
||||
- Multi-Results support (#537)
|
||||
- `rejectReadOnly` DSN option (#604)
|
||||
- `context.Context` support (#608, #612, #627, #761)
|
||||
- Transaction isolation level support (#619, #744)
|
||||
- Read-Only transactions support (#618, #634)
|
||||
- `NewConfig` function which initializes a config with default values (#679)
|
||||
- Implemented the `ColumnType` interfaces (#667, #724)
|
||||
- Support for custom string types in `ConvertValue` (#623)
|
||||
- Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710)
|
||||
- `caching_sha2_password` authentication plugin support (#794, #800, #801, #802)
|
||||
- Implemented `driver.SessionResetter` (#779)
|
||||
- `sha256_password` authentication plugin support (#808)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718)
|
||||
- Fixed LOAD LOCAL DATA INFILE for empty files (#590)
|
||||
- Removed columns definition cache since it sometimes cached invalid data (#592)
|
||||
- Don't mutate registered TLS configs (#600)
|
||||
- Make RegisterTLSConfig concurrency-safe (#613)
|
||||
- Handle missing auth data in the handshake packet correctly (#646)
|
||||
- Do not retry queries when data was written to avoid data corruption (#302, #736)
|
||||
- Cache the connection pointer for error handling before invalidating it (#678)
|
||||
- Fixed imports for appengine/cloudsql (#700)
|
||||
- Fix sending STMT_LONG_DATA for 0 byte data (#734)
|
||||
- Set correct capacity for []bytes read from length-encoded strings (#766)
|
||||
- Make RegisterDial concurrency-safe (#773)
|
||||
|
||||
|
||||
## Version 1.3 (2016-12-01)
|
||||
|
||||
Changes:
|
||||
|
||||
- Go 1.1 is no longer supported
|
||||
- Use decimals fields in MySQL to format time types (#249)
|
||||
- Buffer optimizations (#269)
|
||||
- TLS ServerName defaults to the host (#283)
|
||||
- Refactoring (#400, #410, #437)
|
||||
- Adjusted documentation for second generation CloudSQL (#485)
|
||||
- Documented DSN system var quoting rules (#502)
|
||||
- Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512)
|
||||
|
||||
New Features:
|
||||
|
||||
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
|
||||
- Support for returning table alias on Columns() (#289, #359, #382)
|
||||
- Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490)
|
||||
- Support for uint64 parameters with high bit set (#332, #345)
|
||||
- Cleartext authentication plugin support (#327)
|
||||
- Exported ParseDSN function and the Config struct (#403, #419, #429)
|
||||
- Read / Write timeouts (#401)
|
||||
- Support for JSON field type (#414)
|
||||
- Support for multi-statements and multi-results (#411, #431)
|
||||
- DSN parameter to set the driver-side max_allowed_packet value manually (#489)
|
||||
- Native password authentication plugin support (#494, #524)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fixed handling of queries without columns and rows (#255)
|
||||
- Fixed a panic when SetKeepAlive() failed (#298)
|
||||
- Handle ERR packets while reading rows (#321)
|
||||
- Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)
|
||||
- Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)
|
||||
- Actually zero out bytes in handshake response (#378)
|
||||
- Fixed race condition in registering LOAD DATA INFILE handler (#383)
|
||||
- Fixed tests with MySQL 5.7.9+ (#380)
|
||||
- QueryUnescape TLS config names (#397)
|
||||
- Fixed "broken pipe" error by writing to closed socket (#390)
|
||||
- Fixed LOAD LOCAL DATA INFILE buffering (#424)
|
||||
- Fixed parsing of floats into float64 when placeholders are used (#434)
|
||||
- Fixed DSN tests with Go 1.7+ (#459)
|
||||
- Handle ERR packets while waiting for EOF (#473)
|
||||
- Invalidate connection on error while discarding additional results (#513)
|
||||
- Allow terminating packets of length 0 (#516)
|
||||
|
||||
|
||||
## Version 1.2 (2014-06-03)
|
||||
|
||||
Changes:
|
||||
|
||||
- We switched back to a "rolling release". `go get` installs the current master branch again
|
||||
- Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver
|
||||
- Exported errors to allow easy checking from application code
|
||||
- Enabled TCP Keepalives on TCP connections
|
||||
- Optimized INFILE handling (better buffer size calculation, lazy init, ...)
|
||||
- The DSN parser also checks for a missing separating slash
|
||||
- Faster binary date / datetime to string formatting
|
||||
- Also exported the MySQLWarning type
|
||||
- mysqlConn.Close returns the first error encountered instead of ignoring all errors
|
||||
- writePacket() automatically writes the packet size to the header
|
||||
- readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets
|
||||
|
||||
New Features:
|
||||
|
||||
- `RegisterDial` allows the usage of a custom dial function to establish the network connection
|
||||
- Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter
|
||||
- Logging of critical errors is configurable with `SetLogger`
|
||||
- Google CloudSQL support
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Allow more than 32 parameters in prepared statements
|
||||
- Various old_password fixes
|
||||
- Fixed TestConcurrent test to pass Go's race detection
|
||||
- Fixed appendLengthEncodedInteger for large numbers
|
||||
- Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo)
|
||||
|
||||
|
||||
## Version 1.1 (2013-11-02)
|
||||
|
||||
Changes:
|
||||
|
||||
- Go-MySQL-Driver now requires Go 1.1
|
||||
- Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore
|
||||
- Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors
|
||||
- `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")`
|
||||
- DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'.
|
||||
- Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries
|
||||
- Optimized the buffer for reading
|
||||
- stmt.Query now caches column metadata
|
||||
- New Logo
|
||||
- Changed the copyright header to include all contributors
|
||||
- Improved the LOAD INFILE documentation
|
||||
- The driver struct is now exported to make the driver directly accessible
|
||||
- Refactored the driver tests
|
||||
- Added more benchmarks and moved all to a separate file
|
||||
- Other small refactoring
|
||||
|
||||
New Features:
|
||||
|
||||
- Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure
|
||||
- Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs
|
||||
- Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification
|
||||
- Convert to DB timezone when inserting `time.Time`
|
||||
- Splitted packets (more than 16MB) are now merged correctly
|
||||
- Fixed false positive `io.EOF` errors when the data was fully read
|
||||
- Avoid panics on reuse of closed connections
|
||||
- Fixed empty string producing false nil values
|
||||
- Fixed sign byte for positive TIME fields
|
||||
|
||||
|
||||
## Version 1.0 (2013-05-14)
|
||||
|
||||
Initial Release
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue