vendor: revendor
This commit is contained in:
18
vendor/google.golang.org/grpc/.travis.yml
generated
vendored
18
vendor/google.golang.org/grpc/.travis.yml
generated
vendored
@@ -1,18 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5.4
|
||||
- 1.6.3
|
||||
- 1.7
|
||||
|
||||
go_import_path: google.golang.org/grpc
|
||||
|
||||
before_install:
|
||||
- go get -u golang.org/x/tools/cmd/goimports github.com/golang/lint/golint github.com/axw/gocov/gocov github.com/mattn/goveralls golang.org/x/tools/cmd/cover
|
||||
|
||||
script:
|
||||
- '! gofmt -s -d -l . 2>&1 | read'
|
||||
- '! goimports -l . | read'
|
||||
- '! golint ./... | grep -vE "(_string|\.pb)\.go:"'
|
||||
- '! go tool vet -all . 2>&1 | grep -vE "constant [0-9]+ not a string in call to Errorf" | grep -vF .pb.go:' # https://github.com/golang/protobuf/issues/214
|
||||
- make test testrace
|
46
vendor/google.golang.org/grpc/CONTRIBUTING.md
generated
vendored
46
vendor/google.golang.org/grpc/CONTRIBUTING.md
generated
vendored
@@ -1,46 +0,0 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to grpc! Here are some guidelines
|
||||
and information about how to do so.
|
||||
|
||||
## Sending patches
|
||||
|
||||
### Getting started
|
||||
|
||||
1. Check out the code:
|
||||
|
||||
$ go get google.golang.org/grpc
|
||||
$ cd $GOPATH/src/google.golang.org/grpc
|
||||
|
||||
1. Create a fork of the grpc-go repository.
|
||||
1. Add your fork as a remote:
|
||||
|
||||
$ git remote add fork git@github.com:$YOURGITHUBUSERNAME/grpc-go.git
|
||||
|
||||
1. Make changes, commit them.
|
||||
1. Run the test suite:
|
||||
|
||||
$ make test
|
||||
|
||||
1. Push your changes to your fork:
|
||||
|
||||
$ git push fork ...
|
||||
|
||||
1. Open a pull request.
|
||||
|
||||
## Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
## Filing Issues
|
||||
When filing an issue, make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
### Contributing code
|
||||
Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file.
|
52
vendor/google.golang.org/grpc/Makefile
generated
vendored
52
vendor/google.golang.org/grpc/Makefile
generated
vendored
@@ -1,52 +0,0 @@
|
||||
all: test testrace
|
||||
|
||||
deps:
|
||||
go get -d -v google.golang.org/grpc/...
|
||||
|
||||
updatedeps:
|
||||
go get -d -v -u -f google.golang.org/grpc/...
|
||||
|
||||
testdeps:
|
||||
go get -d -v -t google.golang.org/grpc/...
|
||||
|
||||
updatetestdeps:
|
||||
go get -d -v -t -u -f google.golang.org/grpc/...
|
||||
|
||||
build: deps
|
||||
go build google.golang.org/grpc/...
|
||||
|
||||
proto:
|
||||
@ if ! which protoc > /dev/null; then \
|
||||
echo "error: protoc not installed" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
go get -u -v github.com/golang/protobuf/protoc-gen-go
|
||||
# use $$dir as the root for all proto files in the same directory
|
||||
for dir in $$(git ls-files '*.proto' | xargs -n1 dirname | uniq); do \
|
||||
protoc -I $$dir --go_out=plugins=grpc:$$dir $$dir/*.proto; \
|
||||
done
|
||||
|
||||
test: testdeps
|
||||
go test -v -cpu 1,4 google.golang.org/grpc/...
|
||||
|
||||
testrace: testdeps
|
||||
go test -v -race -cpu 1,4 google.golang.org/grpc/...
|
||||
|
||||
clean:
|
||||
go clean -i google.golang.org/grpc/...
|
||||
|
||||
coverage: testdeps
|
||||
./coverage.sh --coveralls
|
||||
|
||||
.PHONY: \
|
||||
all \
|
||||
deps \
|
||||
updatedeps \
|
||||
testdeps \
|
||||
updatetestdeps \
|
||||
build \
|
||||
proto \
|
||||
test \
|
||||
testrace \
|
||||
clean \
|
||||
coverage
|
32
vendor/google.golang.org/grpc/README.md
generated
vendored
32
vendor/google.golang.org/grpc/README.md
generated
vendored
@@ -1,32 +0,0 @@
|
||||
#gRPC-Go
|
||||
|
||||
[](https://travis-ci.org/grpc/grpc-go) [](https://godoc.org/google.golang.org/grpc)
|
||||
|
||||
The Go implementation of [gRPC](http://www.grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the [gRPC Quick Start](http://www.grpc.io/docs/) guide.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To install this package, you need to install Go and setup your Go workspace on your computer. The simplest way to install the library is to run:
|
||||
|
||||
```
|
||||
$ go get google.golang.org/grpc
|
||||
```
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
This requires Go 1.5 or later .
|
||||
|
||||
Constraints
|
||||
-----------
|
||||
The grpc package should only depend on standard Go packages and a small number of exceptions. If your contribution introduces new dependencies which are NOT in the [list](http://godoc.org/google.golang.org/grpc?imports), you need a discussion with gRPC-Go authors and consultants.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
See [API documentation](https://godoc.org/google.golang.org/grpc) for package and API descriptions and find examples in the [examples directory](examples/).
|
||||
|
||||
Status
|
||||
------
|
||||
GA
|
||||
|
11
vendor/google.golang.org/grpc/backoff_test.go
generated
vendored
11
vendor/google.golang.org/grpc/backoff_test.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBackoffConfigDefaults(t *testing.T) {
|
||||
b := BackoffConfig{}
|
||||
setDefaults(&b)
|
||||
if b != DefaultBackoffConfig {
|
||||
t.Fatalf("expected BackoffConfig to pickup default parameters: %v != %v", b, DefaultBackoffConfig)
|
||||
}
|
||||
}
|
438
vendor/google.golang.org/grpc/balancer_test.go
generated
vendored
438
vendor/google.golang.org/grpc/balancer_test.go
generated
vendored
@@ -1,438 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/naming"
|
||||
)
|
||||
|
||||
type testWatcher struct {
|
||||
// the channel to receives name resolution updates
|
||||
update chan *naming.Update
|
||||
// the side channel to get to know how many updates in a batch
|
||||
side chan int
|
||||
// the channel to notifiy update injector that the update reading is done
|
||||
readDone chan int
|
||||
}
|
||||
|
||||
func (w *testWatcher) Next() (updates []*naming.Update, err error) {
|
||||
n := <-w.side
|
||||
if n == 0 {
|
||||
return nil, fmt.Errorf("w.side is closed")
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
u := <-w.update
|
||||
if u != nil {
|
||||
updates = append(updates, u)
|
||||
}
|
||||
}
|
||||
w.readDone <- 0
|
||||
return
|
||||
}
|
||||
|
||||
func (w *testWatcher) Close() {
|
||||
}
|
||||
|
||||
// Inject naming resolution updates to the testWatcher.
|
||||
func (w *testWatcher) inject(updates []*naming.Update) {
|
||||
w.side <- len(updates)
|
||||
for _, u := range updates {
|
||||
w.update <- u
|
||||
}
|
||||
<-w.readDone
|
||||
}
|
||||
|
||||
type testNameResolver struct {
|
||||
w *testWatcher
|
||||
addr string
|
||||
}
|
||||
|
||||
func (r *testNameResolver) Resolve(target string) (naming.Watcher, error) {
|
||||
r.w = &testWatcher{
|
||||
update: make(chan *naming.Update, 1),
|
||||
side: make(chan int, 1),
|
||||
readDone: make(chan int),
|
||||
}
|
||||
r.w.side <- 1
|
||||
r.w.update <- &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: r.addr,
|
||||
}
|
||||
go func() {
|
||||
<-r.w.readDone
|
||||
}()
|
||||
return r.w, nil
|
||||
}
|
||||
|
||||
func startServers(t *testing.T, numServers int, maxStreams uint32) ([]*server, *testNameResolver) {
|
||||
var servers []*server
|
||||
for i := 0; i < numServers; i++ {
|
||||
s := newTestServer()
|
||||
servers = append(servers, s)
|
||||
go s.start(t, 0, maxStreams)
|
||||
s.wait(t, 2*time.Second)
|
||||
}
|
||||
// Point to server[0]
|
||||
addr := "127.0.0.1:" + servers[0].port
|
||||
return servers, &testNameResolver{
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameDiscovery(t *testing.T) {
|
||||
// Start 2 servers on 2 ports.
|
||||
numServers := 2
|
||||
servers, r := startServers(t, numServers, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
req := "port"
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err == nil || ErrorDesc(err) != servers[0].port {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want %s", err, servers[0].port)
|
||||
}
|
||||
// Inject the name resolution change to remove servers[0] and add servers[1].
|
||||
var updates []*naming.Update
|
||||
updates = append(updates, &naming.Update{
|
||||
Op: naming.Delete,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
})
|
||||
updates = append(updates, &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[1].port,
|
||||
})
|
||||
r.w.inject(updates)
|
||||
// Loop until the rpcs in flight talks to servers[1].
|
||||
for {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
cc.Close()
|
||||
for i := 0; i < numServers; i++ {
|
||||
servers[i].stop()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyAddrs(t *testing.T) {
|
||||
servers, r := startServers(t, 1, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, reply = %q, want %q, <nil>", err, reply, expectedResponse)
|
||||
}
|
||||
// Inject name resolution change to remove the server so that there is no address
|
||||
// available after that.
|
||||
u := &naming.Update{
|
||||
Op: naming.Delete,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
}
|
||||
r.w.inject([]*naming.Update{u})
|
||||
// Loop until the above updates apply.
|
||||
for {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
cc.Close()
|
||||
servers[0].stop()
|
||||
}
|
||||
|
||||
func TestRoundRobin(t *testing.T) {
|
||||
// Start 3 servers on 3 ports.
|
||||
numServers := 3
|
||||
servers, r := startServers(t, numServers, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
// Add servers[1] to the service discovery.
|
||||
u := &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[1].port,
|
||||
}
|
||||
r.w.inject([]*naming.Update{u})
|
||||
req := "port"
|
||||
var reply string
|
||||
// Loop until servers[1] is up
|
||||
for {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
// Add server2[2] to the service discovery.
|
||||
u = &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[2].port,
|
||||
}
|
||||
r.w.inject([]*naming.Update{u})
|
||||
// Loop until both servers[2] are up.
|
||||
for {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[2].port {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
// Check the incoming RPCs served in a round-robin manner.
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err == nil || ErrorDesc(err) != servers[i%numServers].port {
|
||||
t.Fatalf("Index %d: Invoke(_, _, _, _, _) = %v, want %s", i, err, servers[i%numServers].port)
|
||||
}
|
||||
}
|
||||
cc.Close()
|
||||
for i := 0; i < numServers; i++ {
|
||||
servers[i].stop()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseWithPendingRPC(t *testing.T) {
|
||||
servers, r := startServers(t, 1, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err != nil {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want %s", err, servers[0].port)
|
||||
}
|
||||
// Remove the server.
|
||||
updates := []*naming.Update{{
|
||||
Op: naming.Delete,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
}}
|
||||
r.w.inject(updates)
|
||||
// Loop until the above update applies.
|
||||
for {
|
||||
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); Code(err) == codes.DeadlineExceeded {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
// Issue 2 RPCs which should be completed with error status once cc is closed.
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err == nil {
|
||||
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want not nil", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var reply string
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err == nil {
|
||||
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want not nil", err)
|
||||
}
|
||||
}()
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
cc.Close()
|
||||
wg.Wait()
|
||||
servers[0].stop()
|
||||
}
|
||||
|
||||
func TestGetOnWaitChannel(t *testing.T) {
|
||||
servers, r := startServers(t, 1, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
// Remove all servers so that all upcoming RPCs will block on waitCh.
|
||||
updates := []*naming.Update{{
|
||||
Op: naming.Delete,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
}}
|
||||
r.w.inject(updates)
|
||||
for {
|
||||
var reply string
|
||||
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); Code(err) == codes.DeadlineExceeded {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err != nil {
|
||||
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
|
||||
}
|
||||
}()
|
||||
// Add a connected server to get the above RPC through.
|
||||
updates = []*naming.Update{{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
}}
|
||||
r.w.inject(updates)
|
||||
// Wait until the above RPC succeeds.
|
||||
wg.Wait()
|
||||
cc.Close()
|
||||
servers[0].stop()
|
||||
}
|
||||
|
||||
func TestOneServerDown(t *testing.T) {
|
||||
// Start 2 servers.
|
||||
numServers := 2
|
||||
servers, r := startServers(t, numServers, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
// Add servers[1] to the service discovery.
|
||||
var updates []*naming.Update
|
||||
updates = append(updates, &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[1].port,
|
||||
})
|
||||
r.w.inject(updates)
|
||||
req := "port"
|
||||
var reply string
|
||||
// Loop until servers[1] is up
|
||||
for {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
numRPC := 100
|
||||
sleepDuration := 10 * time.Millisecond
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
time.Sleep(sleepDuration)
|
||||
// After sleepDuration, kill server[0].
|
||||
servers[0].stop()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
// All non-failfast RPCs should not block because there's at least one connection available.
|
||||
for i := 0; i < numRPC; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
time.Sleep(sleepDuration)
|
||||
// After sleepDuration, invoke RPC.
|
||||
// server[0] is killed around the same time to make it racy between balancer and gRPC internals.
|
||||
Invoke(context.Background(), "/foo/bar", &req, &reply, cc, FailFast(false))
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
cc.Close()
|
||||
for i := 0; i < numServers; i++ {
|
||||
servers[i].stop()
|
||||
}
|
||||
}
|
||||
|
||||
func TestOneAddressRemoval(t *testing.T) {
|
||||
// Start 2 servers.
|
||||
numServers := 2
|
||||
servers, r := startServers(t, numServers, math.MaxUint32)
|
||||
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
// Add servers[1] to the service discovery.
|
||||
var updates []*naming.Update
|
||||
updates = append(updates, &naming.Update{
|
||||
Op: naming.Add,
|
||||
Addr: "127.0.0.1:" + servers[1].port,
|
||||
})
|
||||
r.w.inject(updates)
|
||||
req := "port"
|
||||
var reply string
|
||||
// Loop until servers[1] is up
|
||||
for {
|
||||
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
numRPC := 100
|
||||
sleepDuration := 10 * time.Millisecond
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
time.Sleep(sleepDuration)
|
||||
// After sleepDuration, delete server[0].
|
||||
var updates []*naming.Update
|
||||
updates = append(updates, &naming.Update{
|
||||
Op: naming.Delete,
|
||||
Addr: "127.0.0.1:" + servers[0].port,
|
||||
})
|
||||
r.w.inject(updates)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
// All non-failfast RPCs should not fail because there's at least one connection available.
|
||||
for i := 0; i < numRPC; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
var reply string
|
||||
time.Sleep(sleepDuration)
|
||||
// After sleepDuration, invoke RPC.
|
||||
// server[0] is removed around the same time to make it racy between balancer and gRPC internals.
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err != nil {
|
||||
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want not nil", err)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
cc.Close()
|
||||
for i := 0; i < numServers; i++ {
|
||||
servers[i].stop()
|
||||
}
|
||||
}
|
293
vendor/google.golang.org/grpc/call_test.go
generated
vendored
293
vendor/google.golang.org/grpc/call_test.go
generated
vendored
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/transport"
|
||||
)
|
||||
|
||||
var (
|
||||
expectedRequest = "ping"
|
||||
expectedResponse = "pong"
|
||||
weirdError = "format verbs: %v%s"
|
||||
sizeLargeErr = 1024 * 1024
|
||||
canceled = 0
|
||||
)
|
||||
|
||||
type testCodec struct {
|
||||
}
|
||||
|
||||
func (testCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return []byte(*(v.(*string))), nil
|
||||
}
|
||||
|
||||
func (testCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
*(v.(*string)) = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (testCodec) String() string {
|
||||
return "test"
|
||||
}
|
||||
|
||||
type testStreamHandler struct {
|
||||
port string
|
||||
t transport.ServerTransport
|
||||
}
|
||||
|
||||
func (h *testStreamHandler) handleStream(t *testing.T, s *transport.Stream) {
|
||||
p := &parser{r: s}
|
||||
for {
|
||||
pf, req, err := p.recvMsg(math.MaxInt32)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if pf != compressionNone {
|
||||
t.Errorf("Received the mistaken message format %d, want %d", pf, compressionNone)
|
||||
return
|
||||
}
|
||||
var v string
|
||||
codec := testCodec{}
|
||||
if err := codec.Unmarshal(req, &v); err != nil {
|
||||
t.Errorf("Failed to unmarshal the received message: %v", err)
|
||||
return
|
||||
}
|
||||
if v == "weird error" {
|
||||
h.t.WriteStatus(s, codes.Internal, weirdError)
|
||||
return
|
||||
}
|
||||
if v == "canceled" {
|
||||
canceled++
|
||||
h.t.WriteStatus(s, codes.Internal, "")
|
||||
return
|
||||
}
|
||||
if v == "port" {
|
||||
h.t.WriteStatus(s, codes.Internal, h.port)
|
||||
return
|
||||
}
|
||||
|
||||
if v != expectedRequest {
|
||||
h.t.WriteStatus(s, codes.Internal, strings.Repeat("A", sizeLargeErr))
|
||||
return
|
||||
}
|
||||
}
|
||||
// send a response back to end the stream.
|
||||
reply, err := encode(testCodec{}, &expectedResponse, nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to encode the response: %v", err)
|
||||
return
|
||||
}
|
||||
h.t.Write(s, reply, &transport.Options{})
|
||||
h.t.WriteStatus(s, codes.OK, "")
|
||||
}
|
||||
|
||||
type server struct {
|
||||
lis net.Listener
|
||||
port string
|
||||
startedErr chan error // sent nil or an error after server starts
|
||||
mu sync.Mutex
|
||||
conns map[transport.ServerTransport]bool
|
||||
}
|
||||
|
||||
func newTestServer() *server {
|
||||
return &server{startedErr: make(chan error, 1)}
|
||||
}
|
||||
|
||||
// start starts server. Other goroutines should block on s.startedErr for further operations.
|
||||
func (s *server) start(t *testing.T, port int, maxStreams uint32) {
|
||||
var err error
|
||||
if port == 0 {
|
||||
s.lis, err = net.Listen("tcp", "localhost:0")
|
||||
} else {
|
||||
s.lis, err = net.Listen("tcp", "localhost:"+strconv.Itoa(port))
|
||||
}
|
||||
if err != nil {
|
||||
s.startedErr <- fmt.Errorf("failed to listen: %v", err)
|
||||
return
|
||||
}
|
||||
_, p, err := net.SplitHostPort(s.lis.Addr().String())
|
||||
if err != nil {
|
||||
s.startedErr <- fmt.Errorf("failed to parse listener address: %v", err)
|
||||
return
|
||||
}
|
||||
s.port = p
|
||||
s.conns = make(map[transport.ServerTransport]bool)
|
||||
s.startedErr <- nil
|
||||
for {
|
||||
conn, err := s.lis.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st, err := transport.NewServerTransport("http2", conn, maxStreams, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s.mu.Lock()
|
||||
if s.conns == nil {
|
||||
s.mu.Unlock()
|
||||
st.Close()
|
||||
return
|
||||
}
|
||||
s.conns[st] = true
|
||||
s.mu.Unlock()
|
||||
h := &testStreamHandler{
|
||||
port: s.port,
|
||||
t: st,
|
||||
}
|
||||
go st.HandleStreams(func(s *transport.Stream) {
|
||||
go h.handleStream(t, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) wait(t *testing.T, timeout time.Duration) {
|
||||
select {
|
||||
case err := <-s.startedErr:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
t.Fatalf("Timed out after %v waiting for server to be ready", timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) stop() {
|
||||
s.lis.Close()
|
||||
s.mu.Lock()
|
||||
for c := range s.conns {
|
||||
c.Close()
|
||||
}
|
||||
s.conns = nil
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func setUp(t *testing.T, port int, maxStreams uint32) (*server, *ClientConn) {
|
||||
server := newTestServer()
|
||||
go server.start(t, port, maxStreams)
|
||||
server.wait(t, 2*time.Second)
|
||||
addr := "localhost:" + server.port
|
||||
cc, err := Dial(addr, WithBlock(), WithInsecure(), WithCodec(testCodec{}))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create ClientConn: %v", err)
|
||||
}
|
||||
return server, cc
|
||||
}
|
||||
|
||||
func TestInvoke(t *testing.T) {
|
||||
server, cc := setUp(t, 0, math.MaxUint32)
|
||||
var reply string
|
||||
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
|
||||
}
|
||||
cc.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestInvokeLargeErr(t *testing.T) {
|
||||
server, cc := setUp(t, 0, math.MaxUint32)
|
||||
var reply string
|
||||
req := "hello"
|
||||
err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc)
|
||||
if _, ok := err.(*rpcError); !ok {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) receives non rpc error.")
|
||||
}
|
||||
if Code(err) != codes.Internal || len(ErrorDesc(err)) != sizeLargeErr {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want an error of code %d and desc size %d", err, codes.Internal, sizeLargeErr)
|
||||
}
|
||||
cc.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
// TestInvokeErrorSpecialChars checks that error messages don't get mangled.
|
||||
func TestInvokeErrorSpecialChars(t *testing.T) {
|
||||
server, cc := setUp(t, 0, math.MaxUint32)
|
||||
var reply string
|
||||
req := "weird error"
|
||||
err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc)
|
||||
if _, ok := err.(*rpcError); !ok {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) receives non rpc error.")
|
||||
}
|
||||
if got, want := ErrorDesc(err), weirdError; got != want {
|
||||
t.Fatalf("grpc.Invoke(_, _, _, _, _) error = %q, want %q", got, want)
|
||||
}
|
||||
cc.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
// TestInvokeCancel checks that an Invoke with a canceled context is not sent.
|
||||
func TestInvokeCancel(t *testing.T) {
|
||||
server, cc := setUp(t, 0, math.MaxUint32)
|
||||
var reply string
|
||||
req := "canceled"
|
||||
for i := 0; i < 100; i++ {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
Invoke(ctx, "/foo/bar", &req, &reply, cc)
|
||||
}
|
||||
if canceled != 0 {
|
||||
t.Fatalf("received %d of 100 canceled requests", canceled)
|
||||
}
|
||||
cc.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
// TestInvokeCancelClosedNonFail checks that a canceled non-failfast RPC
|
||||
// on a closed client will terminate.
|
||||
func TestInvokeCancelClosedNonFailFast(t *testing.T) {
|
||||
server, cc := setUp(t, 0, math.MaxUint32)
|
||||
var reply string
|
||||
cc.Close()
|
||||
req := "hello"
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
if err := Invoke(ctx, "/foo/bar", &req, &reply, cc, FailFast(false)); err == nil {
|
||||
t.Fatalf("canceled invoke on closed connection should fail")
|
||||
}
|
||||
server.stop()
|
||||
}
|
190
vendor/google.golang.org/grpc/clientconn_test.go
generated
vendored
190
vendor/google.golang.org/grpc/clientconn_test.go
generated
vendored
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/oauth"
|
||||
)
|
||||
|
||||
const tlsDir = "testdata/"
|
||||
|
||||
func TestDialTimeout(t *testing.T) {
|
||||
conn, err := Dial("Non-Existent.Server:80", WithTimeout(time.Millisecond), WithBlock(), WithInsecure())
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
}
|
||||
if err != ErrClientConnTimeout {
|
||||
t.Fatalf("Dial(_, _) = %v, %v, want %v", conn, err, ErrClientConnTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSDialTimeout(t *testing.T) {
|
||||
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create credentials %v", err)
|
||||
}
|
||||
conn, err := Dial("Non-Existent.Server:80", WithTransportCredentials(creds), WithTimeout(time.Millisecond), WithBlock())
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
}
|
||||
if err != ErrClientConnTimeout {
|
||||
t.Fatalf("Dial(_, _) = %v, %v, want %v", conn, err, ErrClientConnTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSServerNameOverwrite(t *testing.T) {
|
||||
overwriteServerName := "over.write.server.name"
|
||||
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", overwriteServerName)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create credentials %v", err)
|
||||
}
|
||||
conn, err := Dial("Non-Existent.Server:80", WithTransportCredentials(creds))
|
||||
if err != nil {
|
||||
t.Fatalf("Dial(_, _) = _, %v, want _, <nil>", err)
|
||||
}
|
||||
conn.Close()
|
||||
if conn.authority != overwriteServerName {
|
||||
t.Fatalf("%v.authority = %v, want %v", conn, conn.authority, overwriteServerName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialContextCancel(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
if _, err := DialContext(ctx, "Non-Existent.Server:80", WithBlock(), WithInsecure()); err != context.Canceled {
|
||||
t.Fatalf("DialContext(%v, _) = _, %v, want _, %v", ctx, err, context.Canceled)
|
||||
}
|
||||
}
|
||||
|
||||
// blockingBalancer mimics the behavior of balancers whose initialization takes a long time.
|
||||
// In this test, reading from blockingBalancer.Notify() blocks forever.
|
||||
type blockingBalancer struct {
|
||||
ch chan []Address
|
||||
}
|
||||
|
||||
func newBlockingBalancer() Balancer {
|
||||
return &blockingBalancer{ch: make(chan []Address)}
|
||||
}
|
||||
func (b *blockingBalancer) Start(target string, config BalancerConfig) error {
|
||||
return nil
|
||||
}
|
||||
func (b *blockingBalancer) Up(addr Address) func(error) {
|
||||
return nil
|
||||
}
|
||||
func (b *blockingBalancer) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) {
|
||||
return Address{}, nil, nil
|
||||
}
|
||||
func (b *blockingBalancer) Notify() <-chan []Address {
|
||||
return b.ch
|
||||
}
|
||||
func (b *blockingBalancer) Close() error {
|
||||
close(b.ch)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestDialWithBlockingBalancer(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
dialDone := make(chan struct{})
|
||||
go func() {
|
||||
DialContext(ctx, "Non-Existent.Server:80", WithBlock(), WithInsecure(), WithBalancer(newBlockingBalancer()))
|
||||
close(dialDone)
|
||||
}()
|
||||
cancel()
|
||||
<-dialDone
|
||||
}
|
||||
|
||||
func TestCredentialsMisuse(t *testing.T) {
|
||||
tlsCreds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create authenticator %v", err)
|
||||
}
|
||||
// Two conflicting credential configurations
|
||||
if _, err := Dial("Non-Existent.Server:80", WithTransportCredentials(tlsCreds), WithBlock(), WithInsecure()); err != errCredentialsConflict {
|
||||
t.Fatalf("Dial(_, _) = _, %v, want _, %v", err, errCredentialsConflict)
|
||||
}
|
||||
rpcCreds, err := oauth.NewJWTAccessFromKey(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create credentials %v", err)
|
||||
}
|
||||
// security info on insecure connection
|
||||
if _, err := Dial("Non-Existent.Server:80", WithPerRPCCredentials(rpcCreds), WithBlock(), WithInsecure()); err != errTransportCredentialsMissing {
|
||||
t.Fatalf("Dial(_, _) = _, %v, want _, %v", err, errTransportCredentialsMissing)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithBackoffConfigDefault(t *testing.T) {
|
||||
testBackoffConfigSet(t, &DefaultBackoffConfig)
|
||||
}
|
||||
|
||||
func TestWithBackoffConfig(t *testing.T) {
|
||||
b := BackoffConfig{MaxDelay: DefaultBackoffConfig.MaxDelay / 2}
|
||||
expected := b
|
||||
setDefaults(&expected) // defaults should be set
|
||||
testBackoffConfigSet(t, &expected, WithBackoffConfig(b))
|
||||
}
|
||||
|
||||
func TestWithBackoffMaxDelay(t *testing.T) {
|
||||
md := DefaultBackoffConfig.MaxDelay / 2
|
||||
expected := BackoffConfig{MaxDelay: md}
|
||||
setDefaults(&expected)
|
||||
testBackoffConfigSet(t, &expected, WithBackoffMaxDelay(md))
|
||||
}
|
||||
|
||||
func testBackoffConfigSet(t *testing.T, expected *BackoffConfig, opts ...DialOption) {
|
||||
opts = append(opts, WithInsecure())
|
||||
conn, err := Dial("foo:80", opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error dialing connection: %v", err)
|
||||
}
|
||||
|
||||
if conn.dopts.bs == nil {
|
||||
t.Fatalf("backoff config not set")
|
||||
}
|
||||
|
||||
actual, ok := conn.dopts.bs.(BackoffConfig)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected type of backoff config: %#v", conn.dopts.bs)
|
||||
}
|
||||
|
||||
if actual != *expected {
|
||||
t.Fatalf("unexpected backoff config on connection: %v, want %v", actual, expected)
|
||||
}
|
||||
conn.Close()
|
||||
}
|
17
vendor/google.golang.org/grpc/codegen.sh
generated
vendored
17
vendor/google.golang.org/grpc/codegen.sh
generated
vendored
@@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script serves as an example to demonstrate how to generate the gRPC-Go
|
||||
# interface and the related messages from .proto file.
|
||||
#
|
||||
# It assumes the installation of i) Google proto buffer compiler at
|
||||
# https://github.com/google/protobuf (after v2.6.1) and ii) the Go codegen
|
||||
# plugin at https://github.com/golang/protobuf (after 2015-02-20). If you have
|
||||
# not, please install them first.
|
||||
#
|
||||
# We recommend running this script at $GOPATH/src.
|
||||
#
|
||||
# If this is not what you need, feel free to make your own scripts. Again, this
|
||||
# script is for demonstration purpose.
|
||||
#
|
||||
proto=$1
|
||||
protoc --go_out=plugins=grpc:. $proto
|
47
vendor/google.golang.org/grpc/coverage.sh
generated
vendored
47
vendor/google.golang.org/grpc/coverage.sh
generated
vendored
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
workdir=.cover
|
||||
profile="$workdir/cover.out"
|
||||
mode=set
|
||||
end2endtest="google.golang.org/grpc/test"
|
||||
|
||||
generate_cover_data() {
|
||||
rm -rf "$workdir"
|
||||
mkdir "$workdir"
|
||||
|
||||
for pkg in "$@"; do
|
||||
if [ $pkg == "google.golang.org/grpc" -o $pkg == "google.golang.org/grpc/transport" -o $pkg == "google.golang.org/grpc/metadata" -o $pkg == "google.golang.org/grpc/credentials" ]
|
||||
then
|
||||
f="$workdir/$(echo $pkg | tr / -)"
|
||||
go test -covermode="$mode" -coverprofile="$f.cover" "$pkg"
|
||||
go test -covermode="$mode" -coverpkg "$pkg" -coverprofile="$f.e2e.cover" "$end2endtest"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "mode: $mode" >"$profile"
|
||||
grep -h -v "^mode:" "$workdir"/*.cover >>"$profile"
|
||||
}
|
||||
|
||||
show_cover_report() {
|
||||
go tool cover -${1}="$profile"
|
||||
}
|
||||
|
||||
push_to_coveralls() {
|
||||
goveralls -coverprofile="$profile"
|
||||
}
|
||||
|
||||
generate_cover_data $(go list ./...)
|
||||
show_cover_report func
|
||||
case "$1" in
|
||||
"")
|
||||
;;
|
||||
--html)
|
||||
show_cover_report html ;;
|
||||
--coveralls)
|
||||
push_to_coveralls ;;
|
||||
*)
|
||||
echo >&2 "error: invalid option: $1" ;;
|
||||
esac
|
||||
rm -rf "$workdir"
|
61
vendor/google.golang.org/grpc/credentials/credentials_test.go
generated
vendored
61
vendor/google.golang.org/grpc/credentials/credentials_test.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTLSOverrideServerName(t *testing.T) {
|
||||
expectedServerName := "server.name"
|
||||
c := NewTLS(nil)
|
||||
c.OverrideServerName(expectedServerName)
|
||||
if c.Info().ServerName != expectedServerName {
|
||||
t.Fatalf("c.Info().ServerName = %v, want %v", c.Info().ServerName, expectedServerName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSClone(t *testing.T) {
|
||||
expectedServerName := "server.name"
|
||||
c := NewTLS(nil)
|
||||
c.OverrideServerName(expectedServerName)
|
||||
cc := c.Clone()
|
||||
if cc.Info().ServerName != expectedServerName {
|
||||
t.Fatalf("cc.Info().ServerName = %v, want %v", cc.Info().ServerName, expectedServerName)
|
||||
}
|
||||
cc.OverrideServerName("")
|
||||
if c.Info().ServerName != expectedServerName {
|
||||
t.Fatalf("Change in clone should not affect the original, c.Info().ServerName = %v, want %v", c.Info().ServerName, expectedServerName)
|
||||
}
|
||||
}
|
139
vendor/google.golang.org/grpc/metadata/metadata_test.go
generated
vendored
139
vendor/google.golang.org/grpc/metadata/metadata_test.go
generated
vendored
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const binaryValue = string(128)
|
||||
|
||||
func TestEncodeKeyValue(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
kin string
|
||||
vin string
|
||||
// output
|
||||
kout string
|
||||
vout string
|
||||
}{
|
||||
{"key", "abc", "key", "abc"},
|
||||
{"KEY", "abc", "key", "abc"},
|
||||
{"key-bin", "abc", "key-bin", "YWJj"},
|
||||
{"key-bin", binaryValue, "key-bin", "woA="},
|
||||
} {
|
||||
k, v := encodeKeyValue(test.kin, test.vin)
|
||||
if k != test.kout || !reflect.DeepEqual(v, test.vout) {
|
||||
t.Fatalf("encodeKeyValue(%q, %q) = %q, %q, want %q, %q", test.kin, test.vin, k, v, test.kout, test.vout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeKeyValue(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
kin string
|
||||
vin string
|
||||
// output
|
||||
kout string
|
||||
vout string
|
||||
err error
|
||||
}{
|
||||
{"a", "abc", "a", "abc", nil},
|
||||
{"key-bin", "Zm9vAGJhcg==", "key-bin", "foo\x00bar", nil},
|
||||
{"key-bin", "woA=", "key-bin", binaryValue, nil},
|
||||
{"a", "abc,efg", "a", "abc,efg", nil},
|
||||
{"key-bin", "Zm9vAGJhcg==,Zm9vAGJhcg==", "key-bin", "foo\x00bar,foo\x00bar", nil},
|
||||
} {
|
||||
k, v, err := DecodeKeyValue(test.kin, test.vin)
|
||||
if k != test.kout || !reflect.DeepEqual(v, test.vout) || !reflect.DeepEqual(err, test.err) {
|
||||
t.Fatalf("DecodeKeyValue(%q, %q) = %q, %q, %v, want %q, %q, %v", test.kin, test.vin, k, v, err, test.kout, test.vout, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPairsMD(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
kv []string
|
||||
// output
|
||||
md MD
|
||||
size int
|
||||
}{
|
||||
{[]string{}, MD{}, 0},
|
||||
{[]string{"k1", "v1", "k2-bin", binaryValue}, New(map[string]string{
|
||||
"k1": "v1",
|
||||
"k2-bin": binaryValue,
|
||||
}), 2},
|
||||
} {
|
||||
md := Pairs(test.kv...)
|
||||
if !reflect.DeepEqual(md, test.md) {
|
||||
t.Fatalf("Pairs(%v) = %v, want %v", test.kv, md, test.md)
|
||||
}
|
||||
if md.Len() != test.size {
|
||||
t.Fatalf("Pairs(%v) generates md of size %d, want %d", test.kv, md.Len(), test.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
const key, val = "key", "val"
|
||||
orig := Pairs(key, val)
|
||||
copy := orig.Copy()
|
||||
if !reflect.DeepEqual(orig, copy) {
|
||||
t.Errorf("copied value not equal to the original, got %v, want %v", copy, orig)
|
||||
}
|
||||
orig[key][0] = "foo"
|
||||
if v := copy[key][0]; v != val {
|
||||
t.Errorf("change in original should not affect copy, got %q, want %q", v, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
mds []MD
|
||||
want MD
|
||||
}{
|
||||
{[]MD{}, MD{}},
|
||||
{[]MD{Pairs("foo", "bar")}, Pairs("foo", "bar")},
|
||||
{[]MD{Pairs("foo", "bar"), Pairs("foo", "baz")}, Pairs("foo", "bar", "foo", "baz")},
|
||||
{[]MD{Pairs("foo", "bar"), Pairs("foo", "baz"), Pairs("zip", "zap")}, Pairs("foo", "bar", "foo", "baz", "zip", "zap")},
|
||||
} {
|
||||
md := Join(test.mds...)
|
||||
if !reflect.DeepEqual(md, test.want) {
|
||||
t.Errorf("context's metadata is %v, want %v", md, test.want)
|
||||
}
|
||||
}
|
||||
}
|
234
vendor/google.golang.org/grpc/rpc_util_test.go
generated
vendored
234
vendor/google.golang.org/grpc/rpc_util_test.go
generated
vendored
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
perfpb "google.golang.org/grpc/test/codec_perf"
|
||||
"google.golang.org/grpc/transport"
|
||||
)
|
||||
|
||||
func TestSimpleParsing(t *testing.T) {
|
||||
bigMsg := bytes.Repeat([]byte{'x'}, 1<<24)
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
p []byte
|
||||
// outputs
|
||||
err error
|
||||
b []byte
|
||||
pt payloadFormat
|
||||
}{
|
||||
{nil, io.EOF, nil, compressionNone},
|
||||
{[]byte{0, 0, 0, 0, 0}, nil, nil, compressionNone},
|
||||
{[]byte{0, 0, 0, 0, 1, 'a'}, nil, []byte{'a'}, compressionNone},
|
||||
{[]byte{1, 0}, io.ErrUnexpectedEOF, nil, compressionNone},
|
||||
{[]byte{0, 0, 0, 0, 10, 'a'}, io.ErrUnexpectedEOF, nil, compressionNone},
|
||||
// Check that messages with length >= 2^24 are parsed.
|
||||
{append([]byte{0, 1, 0, 0, 0}, bigMsg...), nil, bigMsg, compressionNone},
|
||||
} {
|
||||
buf := bytes.NewReader(test.p)
|
||||
parser := &parser{r: buf}
|
||||
pt, b, err := parser.recvMsg(math.MaxInt32)
|
||||
if err != test.err || !bytes.Equal(b, test.b) || pt != test.pt {
|
||||
t.Fatalf("parser{%v}.recvMsg(_) = %v, %v, %v\nwant %v, %v, %v", test.p, pt, b, err, test.pt, test.b, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleParsing(t *testing.T) {
|
||||
// Set a byte stream consists of 3 messages with their headers.
|
||||
p := []byte{0, 0, 0, 0, 1, 'a', 0, 0, 0, 0, 2, 'b', 'c', 0, 0, 0, 0, 1, 'd'}
|
||||
b := bytes.NewReader(p)
|
||||
parser := &parser{r: b}
|
||||
|
||||
wantRecvs := []struct {
|
||||
pt payloadFormat
|
||||
data []byte
|
||||
}{
|
||||
{compressionNone, []byte("a")},
|
||||
{compressionNone, []byte("bc")},
|
||||
{compressionNone, []byte("d")},
|
||||
}
|
||||
for i, want := range wantRecvs {
|
||||
pt, data, err := parser.recvMsg(math.MaxInt32)
|
||||
if err != nil || pt != want.pt || !reflect.DeepEqual(data, want.data) {
|
||||
t.Fatalf("after %d calls, parser{%v}.recvMsg(_) = %v, %v, %v\nwant %v, %v, <nil>",
|
||||
i, p, pt, data, err, want.pt, want.data)
|
||||
}
|
||||
}
|
||||
|
||||
pt, data, err := parser.recvMsg(math.MaxInt32)
|
||||
if err != io.EOF {
|
||||
t.Fatalf("after %d recvMsgs calls, parser{%v}.recvMsg(_) = %v, %v, %v\nwant _, _, %v",
|
||||
len(wantRecvs), p, pt, data, err, io.EOF)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
msg proto.Message
|
||||
cp Compressor
|
||||
// outputs
|
||||
b []byte
|
||||
err error
|
||||
}{
|
||||
{nil, nil, []byte{0, 0, 0, 0, 0}, nil},
|
||||
} {
|
||||
b, err := encode(protoCodec{}, test.msg, nil, nil)
|
||||
if err != test.err || !bytes.Equal(b, test.b) {
|
||||
t.Fatalf("encode(_, _, %v, _) = %v, %v\nwant %v, %v", test.cp, b, err, test.b, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompress(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
data []byte
|
||||
cp Compressor
|
||||
dc Decompressor
|
||||
// outputs
|
||||
err error
|
||||
}{
|
||||
{make([]byte, 1024), &gzipCompressor{}, &gzipDecompressor{}, nil},
|
||||
} {
|
||||
b := new(bytes.Buffer)
|
||||
if err := test.cp.Do(b, test.data); err != test.err {
|
||||
t.Fatalf("Compressor.Do(_, %v) = %v, want %v", test.data, err, test.err)
|
||||
}
|
||||
if b.Len() >= len(test.data) {
|
||||
t.Fatalf("The compressor fails to compress data.")
|
||||
}
|
||||
if p, err := test.dc.Do(b); err != nil || !bytes.Equal(test.data, p) {
|
||||
t.Fatalf("Decompressor.Do(%v) = %v, %v, want %v, <nil>", b, p, err, test.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToRPCErr(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
errIn error
|
||||
// outputs
|
||||
errOut *rpcError
|
||||
}{
|
||||
{transport.StreamError{codes.Unknown, ""}, Errorf(codes.Unknown, "").(*rpcError)},
|
||||
{transport.ErrConnClosing, Errorf(codes.Internal, transport.ErrConnClosing.Desc).(*rpcError)},
|
||||
} {
|
||||
err := toRPCErr(test.errIn)
|
||||
rpcErr, ok := err.(*rpcError)
|
||||
if !ok {
|
||||
t.Fatalf("toRPCErr{%v} returned type %T, want %T", test.errIn, err, rpcError{})
|
||||
}
|
||||
if *rpcErr != *test.errOut {
|
||||
t.Fatalf("toRPCErr{%v} = %v \nwant %v", test.errIn, err, test.errOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextErr(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
errIn error
|
||||
// outputs
|
||||
errOut transport.StreamError
|
||||
}{
|
||||
{context.DeadlineExceeded, transport.StreamError{codes.DeadlineExceeded, context.DeadlineExceeded.Error()}},
|
||||
{context.Canceled, transport.StreamError{codes.Canceled, context.Canceled.Error()}},
|
||||
} {
|
||||
err := transport.ContextErr(test.errIn)
|
||||
if err != test.errOut {
|
||||
t.Fatalf("ContextErr{%v} = %v \nwant %v", test.errIn, err, test.errOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsWithSameParameters(t *testing.T) {
|
||||
const description = "some description"
|
||||
e1 := Errorf(codes.AlreadyExists, description).(*rpcError)
|
||||
e2 := Errorf(codes.AlreadyExists, description).(*rpcError)
|
||||
if e1 == e2 {
|
||||
t.Fatalf("Error interfaces should not be considered equal - e1: %p - %v e2: %p - %v", e1, e1, e2, e2)
|
||||
}
|
||||
if Code(e1) != Code(e2) || ErrorDesc(e1) != ErrorDesc(e2) {
|
||||
t.Fatalf("Expected errors to have same code and description - e1: %p - %v e2: %p - %v", e1, e1, e2, e2)
|
||||
}
|
||||
}
|
||||
|
||||
// bmEncode benchmarks encoding a Protocol Buffer message containing mSize
|
||||
// bytes.
|
||||
func bmEncode(b *testing.B, mSize int) {
|
||||
msg := &perfpb.Buffer{Body: make([]byte, mSize)}
|
||||
encoded, _ := encode(protoCodec{}, msg, nil, nil)
|
||||
encodedSz := int64(len(encoded))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
encode(protoCodec{}, msg, nil, nil)
|
||||
}
|
||||
b.SetBytes(encodedSz)
|
||||
}
|
||||
|
||||
func BenchmarkEncode1B(b *testing.B) {
|
||||
bmEncode(b, 1)
|
||||
}
|
||||
|
||||
func BenchmarkEncode1KiB(b *testing.B) {
|
||||
bmEncode(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkEncode8KiB(b *testing.B) {
|
||||
bmEncode(b, 8*1024)
|
||||
}
|
||||
|
||||
func BenchmarkEncode64KiB(b *testing.B) {
|
||||
bmEncode(b, 64*1024)
|
||||
}
|
||||
|
||||
func BenchmarkEncode512KiB(b *testing.B) {
|
||||
bmEncode(b, 512*1024)
|
||||
}
|
||||
|
||||
func BenchmarkEncode1MiB(b *testing.B) {
|
||||
bmEncode(b, 1024*1024)
|
||||
}
|
113
vendor/google.golang.org/grpc/server_test.go
generated
vendored
113
vendor/google.golang.org/grpc/server_test.go
generated
vendored
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type emptyServiceServer interface{}
|
||||
|
||||
type testServer struct{}
|
||||
|
||||
func TestStopBeforeServe(t *testing.T) {
|
||||
lis, err := net.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create listener: %v", err)
|
||||
}
|
||||
|
||||
server := NewServer()
|
||||
server.Stop()
|
||||
err = server.Serve(lis)
|
||||
if err != ErrServerStopped {
|
||||
t.Fatalf("server.Serve() error = %v, want %v", err, ErrServerStopped)
|
||||
}
|
||||
|
||||
// server.Serve is responsible for closing the listener, even if the
|
||||
// server was already stopped.
|
||||
err = lis.Close()
|
||||
if got, want := ErrorDesc(err), "use of closed network connection"; !strings.Contains(got, want) {
|
||||
t.Errorf("Close() error = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceInfo(t *testing.T) {
|
||||
testSd := ServiceDesc{
|
||||
ServiceName: "grpc.testing.EmptyService",
|
||||
HandlerType: (*emptyServiceServer)(nil),
|
||||
Methods: []MethodDesc{
|
||||
{
|
||||
MethodName: "EmptyCall",
|
||||
Handler: nil,
|
||||
},
|
||||
},
|
||||
Streams: []StreamDesc{
|
||||
{
|
||||
StreamName: "EmptyStream",
|
||||
Handler: nil,
|
||||
ServerStreams: false,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: []int{0, 2, 1, 3},
|
||||
}
|
||||
|
||||
server := NewServer()
|
||||
server.RegisterService(&testSd, &testServer{})
|
||||
|
||||
info := server.GetServiceInfo()
|
||||
want := map[string]ServiceInfo{
|
||||
"grpc.testing.EmptyService": {
|
||||
Methods: []MethodInfo{
|
||||
{
|
||||
Name: "EmptyCall",
|
||||
IsClientStream: false,
|
||||
IsServerStream: false,
|
||||
},
|
||||
{
|
||||
Name: "EmptyStream",
|
||||
IsClientStream: true,
|
||||
IsServerStream: false,
|
||||
}},
|
||||
Metadata: []int{0, 2, 1, 3},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(info, want) {
|
||||
t.Errorf("GetServiceInfo() = %+v, want %+v", info, want)
|
||||
}
|
||||
}
|
389
vendor/google.golang.org/grpc/transport/handler_server_test.go
generated
vendored
389
vendor/google.golang.org/grpc/transport/handler_server_test.go
generated
vendored
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
func TestHandlerTransport_NewServerHandlerTransport(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
req *http.Request
|
||||
wantErr string
|
||||
modrw func(http.ResponseWriter) http.ResponseWriter
|
||||
check func(*serverHandlerTransport, *testCase) error
|
||||
}
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "http/1.1",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
},
|
||||
wantErr: "gRPC requires HTTP/2",
|
||||
},
|
||||
{
|
||||
name: "bad method",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "GET",
|
||||
Header: http.Header{},
|
||||
RequestURI: "/",
|
||||
},
|
||||
wantErr: "invalid gRPC request method",
|
||||
},
|
||||
{
|
||||
name: "bad content type",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/foo"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
wantErr: "invalid gRPC request content-type",
|
||||
},
|
||||
{
|
||||
name: "not flusher",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
modrw: func(w http.ResponseWriter) http.ResponseWriter {
|
||||
// Return w without its Flush method
|
||||
type onlyCloseNotifier interface {
|
||||
http.ResponseWriter
|
||||
http.CloseNotifier
|
||||
}
|
||||
return struct{ onlyCloseNotifier }{w.(onlyCloseNotifier)}
|
||||
},
|
||||
wantErr: "gRPC requires a ResponseWriter supporting http.Flusher",
|
||||
},
|
||||
{
|
||||
name: "not closenotifier",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
modrw: func(w http.ResponseWriter) http.ResponseWriter {
|
||||
// Return w without its CloseNotify method
|
||||
type onlyFlusher interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
}
|
||||
return struct{ onlyFlusher }{w.(onlyFlusher)}
|
||||
},
|
||||
wantErr: "gRPC requires a ResponseWriter supporting http.CloseNotifier",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(t *serverHandlerTransport, tt *testCase) error {
|
||||
if t.req != tt.req {
|
||||
return fmt.Errorf("t.req = %p; want %p", t.req, tt.req)
|
||||
}
|
||||
if t.rw == nil {
|
||||
return errors.New("t.rw = nil; want non-nil")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with timeout",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"Grpc-Timeout": {"200m"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(t *serverHandlerTransport, tt *testCase) error {
|
||||
if !t.timeoutSet {
|
||||
return errors.New("timeout not set")
|
||||
}
|
||||
if want := 200 * time.Millisecond; t.timeout != want {
|
||||
return fmt.Errorf("timeout = %v; want %v", t.timeout, want)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with bad timeout",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"Grpc-Timeout": {"tomorrow"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
wantErr: `stream error: code = 13 desc = "malformed time-out: transport: timeout unit is not recognized: \"tomorrow\""`,
|
||||
},
|
||||
{
|
||||
name: "with metadata",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"meta-foo": {"foo-val"},
|
||||
"meta-bar": {"bar-val1", "bar-val2"},
|
||||
"user-agent": {"x/y a/b"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(ht *serverHandlerTransport, tt *testCase) error {
|
||||
want := metadata.MD{
|
||||
"meta-bar": {"bar-val1", "bar-val2"},
|
||||
"user-agent": {"x/y"},
|
||||
"meta-foo": {"foo-val"},
|
||||
}
|
||||
if !reflect.DeepEqual(ht.headerMD, want) {
|
||||
return fmt.Errorf("metdata = %#v; want %#v", ht.headerMD, want)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
rw := newTestHandlerResponseWriter()
|
||||
if tt.modrw != nil {
|
||||
rw = tt.modrw(rw)
|
||||
}
|
||||
got, gotErr := NewServerHandlerTransport(rw, tt.req)
|
||||
if (gotErr != nil) != (tt.wantErr != "") || (gotErr != nil && gotErr.Error() != tt.wantErr) {
|
||||
t.Errorf("%s: error = %v; want %q", tt.name, gotErr, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
if gotErr != nil {
|
||||
continue
|
||||
}
|
||||
if tt.check != nil {
|
||||
if err := tt.check(got.(*serverHandlerTransport), &tt); err != nil {
|
||||
t.Errorf("%s: %v", tt.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testHandlerResponseWriter struct {
|
||||
*httptest.ResponseRecorder
|
||||
closeNotify chan bool
|
||||
}
|
||||
|
||||
func (w testHandlerResponseWriter) CloseNotify() <-chan bool { return w.closeNotify }
|
||||
func (w testHandlerResponseWriter) Flush() {}
|
||||
|
||||
func newTestHandlerResponseWriter() http.ResponseWriter {
|
||||
return testHandlerResponseWriter{
|
||||
ResponseRecorder: httptest.NewRecorder(),
|
||||
closeNotify: make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
type handleStreamTest struct {
|
||||
t *testing.T
|
||||
bodyw *io.PipeWriter
|
||||
req *http.Request
|
||||
rw testHandlerResponseWriter
|
||||
ht *serverHandlerTransport
|
||||
}
|
||||
|
||||
func newHandleStreamTest(t *testing.T) *handleStreamTest {
|
||||
bodyr, bodyw := io.Pipe()
|
||||
req := &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
Body: bodyr,
|
||||
}
|
||||
rw := newTestHandlerResponseWriter().(testHandlerResponseWriter)
|
||||
ht, err := NewServerHandlerTransport(rw, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return &handleStreamTest{
|
||||
t: t,
|
||||
bodyw: bodyw,
|
||||
ht: ht.(*serverHandlerTransport),
|
||||
rw: rw,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerTransport_HandleStreams(t *testing.T) {
|
||||
st := newHandleStreamTest(t)
|
||||
handleStream := func(s *Stream) {
|
||||
if want := "/service/foo.bar"; s.method != want {
|
||||
t.Errorf("stream method = %q; want %q", s.method, want)
|
||||
}
|
||||
st.bodyw.Close() // no body
|
||||
st.ht.WriteStatus(s, codes.OK, "")
|
||||
}
|
||||
st.ht.HandleStreams(func(s *Stream) { go handleStream(s) })
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message"},
|
||||
"Grpc-Status": {"0"},
|
||||
}
|
||||
if !reflect.DeepEqual(st.rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer Map: %#v; want %#v", st.rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that codes.Unimplemented will close the body, per comment in handler_server.go.
|
||||
func TestHandlerTransport_HandleStreams_Unimplemented(t *testing.T) {
|
||||
handleStreamCloseBodyTest(t, codes.Unimplemented, "thingy is unimplemented")
|
||||
}
|
||||
|
||||
// Tests that codes.InvalidArgument will close the body, per comment in handler_server.go.
|
||||
func TestHandlerTransport_HandleStreams_InvalidArgument(t *testing.T) {
|
||||
handleStreamCloseBodyTest(t, codes.InvalidArgument, "bad arg")
|
||||
}
|
||||
|
||||
func handleStreamCloseBodyTest(t *testing.T, statusCode codes.Code, msg string) {
|
||||
st := newHandleStreamTest(t)
|
||||
handleStream := func(s *Stream) {
|
||||
st.ht.WriteStatus(s, statusCode, msg)
|
||||
}
|
||||
st.ht.HandleStreams(func(s *Stream) { go handleStream(s) })
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message"},
|
||||
"Grpc-Status": {fmt.Sprint(uint32(statusCode))},
|
||||
"Grpc-Message": {encodeGrpcMessage(msg)},
|
||||
}
|
||||
if !reflect.DeepEqual(st.rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer mismatch.\n got: %#v\nwant: %#v", st.rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerTransport_HandleStreams_Timeout(t *testing.T) {
|
||||
bodyr, bodyw := io.Pipe()
|
||||
req := &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Grpc-Timeout": {"200m"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
Body: bodyr,
|
||||
}
|
||||
rw := newTestHandlerResponseWriter().(testHandlerResponseWriter)
|
||||
ht, err := NewServerHandlerTransport(rw, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runStream := func(s *Stream) {
|
||||
defer bodyw.Close()
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("timeout waiting for ctx.Done")
|
||||
return
|
||||
}
|
||||
err := s.ctx.Err()
|
||||
if err != context.DeadlineExceeded {
|
||||
t.Errorf("ctx.Err = %v; want %v", err, context.DeadlineExceeded)
|
||||
return
|
||||
}
|
||||
ht.WriteStatus(s, codes.DeadlineExceeded, "too slow")
|
||||
}
|
||||
ht.HandleStreams(func(s *Stream) { go runStream(s) })
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message"},
|
||||
"Grpc-Status": {"4"},
|
||||
"Grpc-Message": {encodeGrpcMessage("too slow")},
|
||||
}
|
||||
if !reflect.DeepEqual(rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer Map mismatch.\n got: %#v\nwant: %#v", rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
145
vendor/google.golang.org/grpc/transport/http_util_test.go
generated
vendored
145
vendor/google.golang.org/grpc/transport/http_util_test.go
generated
vendored
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTimeoutEncode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"12345678ns", "12345678n"},
|
||||
{"123456789ns", "123457u"},
|
||||
{"12345678us", "12345678u"},
|
||||
{"123456789us", "123457m"},
|
||||
{"12345678ms", "12345678m"},
|
||||
{"123456789ms", "123457S"},
|
||||
{"12345678s", "12345678S"},
|
||||
{"123456789s", "2057614M"},
|
||||
{"12345678m", "12345678M"},
|
||||
{"123456789m", "2057614H"},
|
||||
} {
|
||||
d, err := time.ParseDuration(test.in)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse duration string %s: %v", test.in, err)
|
||||
}
|
||||
out := encodeTimeout(d)
|
||||
if out != test.out {
|
||||
t.Fatalf("timeoutEncode(%s) = %s, want %s", test.in, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeoutDecode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
s string
|
||||
// output
|
||||
d time.Duration
|
||||
err error
|
||||
}{
|
||||
{"1234S", time.Second * 1234, nil},
|
||||
{"1234x", 0, fmt.Errorf("transport: timeout unit is not recognized: %q", "1234x")},
|
||||
{"1", 0, fmt.Errorf("transport: timeout string is too short: %q", "1")},
|
||||
{"", 0, fmt.Errorf("transport: timeout string is too short: %q", "")},
|
||||
} {
|
||||
d, err := decodeTimeout(test.s)
|
||||
if d != test.d || fmt.Sprint(err) != fmt.Sprint(test.err) {
|
||||
t.Fatalf("timeoutDecode(%q) = %d, %v, want %d, %v", test.s, int64(d), err, int64(test.d), test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidContentType(t *testing.T) {
|
||||
tests := []struct {
|
||||
h string
|
||||
want bool
|
||||
}{
|
||||
{"application/grpc", true},
|
||||
{"application/grpc+", true},
|
||||
{"application/grpc+blah", true},
|
||||
{"application/grpc;", true},
|
||||
{"application/grpc;blah", true},
|
||||
{"application/grpcd", false},
|
||||
{"application/grpd", false},
|
||||
{"application/grp", false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := validContentType(tt.h)
|
||||
if got != tt.want {
|
||||
t.Errorf("validContentType(%q) = %v; want %v", tt.h, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeGrpcMessage(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Hello", "Hello"},
|
||||
{"my favorite character is \u0000", "my favorite character is %00"},
|
||||
{"my favorite character is %", "my favorite character is %25"},
|
||||
} {
|
||||
actual := encodeGrpcMessage(tt.input)
|
||||
if tt.expected != actual {
|
||||
t.Errorf("encodeGrpcMessage(%v) = %v, want %v", tt.input, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeGrpcMessage(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Hello", "Hello"},
|
||||
{"H%61o", "Hao"},
|
||||
{"H%6", "H%6"},
|
||||
{"%G0", "%G0"},
|
||||
{"%E7%B3%BB%E7%BB%9F", "系统"},
|
||||
} {
|
||||
actual := decodeGrpcMessage(tt.input)
|
||||
if tt.expected != actual {
|
||||
t.Errorf("dncodeGrpcMessage(%v) = %v, want %v", tt.input, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
829
vendor/google.golang.org/grpc/transport/transport_test.go
generated
vendored
829
vendor/google.golang.org/grpc/transport/transport_test.go
generated
vendored
@@ -1,829 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
lis net.Listener
|
||||
port string
|
||||
startedErr chan error // error (or nil) with server start value
|
||||
mu sync.Mutex
|
||||
conns map[ServerTransport]bool
|
||||
}
|
||||
|
||||
var (
|
||||
expectedRequest = []byte("ping")
|
||||
expectedResponse = []byte("pong")
|
||||
expectedRequestLarge = make([]byte, initialWindowSize*2)
|
||||
expectedResponseLarge = make([]byte, initialWindowSize*2)
|
||||
expectedInvalidHeaderField = "invalid/content-type"
|
||||
)
|
||||
|
||||
type testStreamHandler struct {
|
||||
t *http2Server
|
||||
}
|
||||
|
||||
type hType int
|
||||
|
||||
const (
|
||||
normal hType = iota
|
||||
suspended
|
||||
misbehaved
|
||||
encodingRequiredStatus
|
||||
invalidHeaderField
|
||||
)
|
||||
|
||||
func (h *testStreamHandler) handleStream(t *testing.T, s *Stream) {
|
||||
req := expectedRequest
|
||||
resp := expectedResponse
|
||||
if s.Method() == "foo.Large" {
|
||||
req = expectedRequestLarge
|
||||
resp = expectedResponseLarge
|
||||
}
|
||||
p := make([]byte, len(req))
|
||||
_, err := io.ReadFull(s, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !bytes.Equal(p, req) {
|
||||
t.Fatalf("handleStream got %v, want %v", p, req)
|
||||
}
|
||||
// send a response back to the client.
|
||||
h.t.Write(s, resp, &Options{})
|
||||
// send the trailer to end the stream.
|
||||
h.t.WriteStatus(s, codes.OK, "")
|
||||
}
|
||||
|
||||
// handleStreamSuspension blocks until s.ctx is canceled.
|
||||
func (h *testStreamHandler) handleStreamSuspension(s *Stream) {
|
||||
go func() {
|
||||
<-s.ctx.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *testStreamHandler) handleStreamMisbehave(t *testing.T, s *Stream) {
|
||||
conn, ok := s.ServerTransport().(*http2Server)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Server", s.ServerTransport())
|
||||
}
|
||||
var sent int
|
||||
p := make([]byte, http2MaxFrameLen)
|
||||
for sent < initialWindowSize {
|
||||
<-conn.writableChan
|
||||
n := initialWindowSize - sent
|
||||
// The last message may be smaller than http2MaxFrameLen
|
||||
if n <= http2MaxFrameLen {
|
||||
if s.Method() == "foo.Connection" {
|
||||
// Violate connection level flow control window of client but do not
|
||||
// violate any stream level windows.
|
||||
p = make([]byte, n)
|
||||
} else {
|
||||
// Violate stream level flow control window of client.
|
||||
p = make([]byte, n+1)
|
||||
}
|
||||
}
|
||||
if err := conn.framer.writeData(true, s.id, false, p); err != nil {
|
||||
conn.writableChan <- 0
|
||||
break
|
||||
}
|
||||
conn.writableChan <- 0
|
||||
sent += len(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *testStreamHandler) handleStreamEncodingRequiredStatus(t *testing.T, s *Stream) {
|
||||
// raw newline is not accepted by http2 framer so it must be encoded.
|
||||
h.t.WriteStatus(s, encodingTestStatusCode, encodingTestStatusDesc)
|
||||
}
|
||||
|
||||
func (h *testStreamHandler) handleStreamInvalidHeaderField(t *testing.T, s *Stream) {
|
||||
<-h.t.writableChan
|
||||
h.t.hBuf.Reset()
|
||||
h.t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: expectedInvalidHeaderField})
|
||||
if err := h.t.writeHeaders(s, h.t.hBuf, false); err != nil {
|
||||
t.Fatalf("Failed to write headers: %v", err)
|
||||
}
|
||||
h.t.writableChan <- 0
|
||||
}
|
||||
|
||||
// start starts server. Other goroutines should block on s.readyChan for further operations.
|
||||
func (s *server) start(t *testing.T, port int, maxStreams uint32, ht hType) {
|
||||
var err error
|
||||
if port == 0 {
|
||||
s.lis, err = net.Listen("tcp", "localhost:0")
|
||||
} else {
|
||||
s.lis, err = net.Listen("tcp", "localhost:"+strconv.Itoa(port))
|
||||
}
|
||||
if err != nil {
|
||||
s.startedErr <- fmt.Errorf("failed to listen: %v", err)
|
||||
return
|
||||
}
|
||||
_, p, err := net.SplitHostPort(s.lis.Addr().String())
|
||||
if err != nil {
|
||||
s.startedErr <- fmt.Errorf("failed to parse listener address: %v", err)
|
||||
return
|
||||
}
|
||||
s.port = p
|
||||
s.conns = make(map[ServerTransport]bool)
|
||||
s.startedErr <- nil
|
||||
for {
|
||||
conn, err := s.lis.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
transport, err := NewServerTransport("http2", conn, maxStreams, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
if s.conns == nil {
|
||||
s.mu.Unlock()
|
||||
transport.Close()
|
||||
return
|
||||
}
|
||||
s.conns[transport] = true
|
||||
s.mu.Unlock()
|
||||
h := &testStreamHandler{transport.(*http2Server)}
|
||||
switch ht {
|
||||
case suspended:
|
||||
go transport.HandleStreams(h.handleStreamSuspension)
|
||||
case misbehaved:
|
||||
go transport.HandleStreams(func(s *Stream) {
|
||||
go h.handleStreamMisbehave(t, s)
|
||||
})
|
||||
case encodingRequiredStatus:
|
||||
go transport.HandleStreams(func(s *Stream) {
|
||||
go h.handleStreamEncodingRequiredStatus(t, s)
|
||||
})
|
||||
case invalidHeaderField:
|
||||
go transport.HandleStreams(func(s *Stream) {
|
||||
go h.handleStreamInvalidHeaderField(t, s)
|
||||
})
|
||||
default:
|
||||
go transport.HandleStreams(func(s *Stream) {
|
||||
go h.handleStream(t, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) wait(t *testing.T, timeout time.Duration) {
|
||||
select {
|
||||
case err := <-s.startedErr:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
t.Fatalf("Timed out after %v waiting for server to be ready", timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) stop() {
|
||||
s.lis.Close()
|
||||
s.mu.Lock()
|
||||
for c := range s.conns {
|
||||
c.Close()
|
||||
}
|
||||
s.conns = nil
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func setUp(t *testing.T, port int, maxStreams uint32, ht hType) (*server, ClientTransport) {
|
||||
server := &server{startedErr: make(chan error, 1)}
|
||||
go server.start(t, port, maxStreams, ht)
|
||||
server.wait(t, 2*time.Second)
|
||||
addr := "localhost:" + server.port
|
||||
var (
|
||||
ct ClientTransport
|
||||
connErr error
|
||||
)
|
||||
ct, connErr = NewClientTransport(context.Background(), addr, ConnectOptions{})
|
||||
if connErr != nil {
|
||||
t.Fatalf("failed to create transport: %v", connErr)
|
||||
}
|
||||
return server, ct
|
||||
}
|
||||
|
||||
func TestClientSendAndReceive(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, normal)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Small",
|
||||
}
|
||||
s1, err1 := ct.NewStream(context.Background(), callHdr)
|
||||
if err1 != nil {
|
||||
t.Fatalf("failed to open stream: %v", err1)
|
||||
}
|
||||
if s1.id != 1 {
|
||||
t.Fatalf("wrong stream id: %d", s1.id)
|
||||
}
|
||||
s2, err2 := ct.NewStream(context.Background(), callHdr)
|
||||
if err2 != nil {
|
||||
t.Fatalf("failed to open stream: %v", err2)
|
||||
}
|
||||
if s2.id != 3 {
|
||||
t.Fatalf("wrong stream id: %d", s2.id)
|
||||
}
|
||||
opts := Options{
|
||||
Last: true,
|
||||
Delay: false,
|
||||
}
|
||||
if err := ct.Write(s1, expectedRequest, &opts); err != nil && err != io.EOF {
|
||||
t.Fatalf("failed to send data: %v", err)
|
||||
}
|
||||
p := make([]byte, len(expectedResponse))
|
||||
_, recvErr := io.ReadFull(s1, p)
|
||||
if recvErr != nil || !bytes.Equal(p, expectedResponse) {
|
||||
t.Fatalf("Error: %v, want <nil>; Result: %v, want %v", recvErr, p, expectedResponse)
|
||||
}
|
||||
_, recvErr = io.ReadFull(s1, p)
|
||||
if recvErr != io.EOF {
|
||||
t.Fatalf("Error: %v; want <EOF>", recvErr)
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestClientErrorNotify(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, normal)
|
||||
go server.stop()
|
||||
// ct.reader should detect the error and activate ct.Error().
|
||||
<-ct.Error()
|
||||
ct.Close()
|
||||
}
|
||||
|
||||
func performOneRPC(ct ClientTransport) {
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Small",
|
||||
}
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
opts := Options{
|
||||
Last: true,
|
||||
Delay: false,
|
||||
}
|
||||
if err := ct.Write(s, expectedRequest, &opts); err == nil || err == io.EOF {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
// The following s.Recv()'s could error out because the
|
||||
// underlying transport is gone.
|
||||
//
|
||||
// Read response
|
||||
p := make([]byte, len(expectedResponse))
|
||||
io.ReadFull(s, p)
|
||||
// Read io.EOF
|
||||
io.ReadFull(s, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientMix(t *testing.T) {
|
||||
s, ct := setUp(t, 0, math.MaxUint32, normal)
|
||||
go func(s *server) {
|
||||
time.Sleep(5 * time.Second)
|
||||
s.stop()
|
||||
}(s)
|
||||
go func(ct ClientTransport) {
|
||||
<-ct.Error()
|
||||
ct.Close()
|
||||
}(ct)
|
||||
for i := 0; i < 1000; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
go performOneRPC(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLargeMessage(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, normal)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Large",
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 2; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Errorf("%v.NewStream(_, _) = _, %v, want _, <nil>", ct, err)
|
||||
}
|
||||
if err := ct.Write(s, expectedRequestLarge, &Options{Last: true, Delay: false}); err != nil && err != io.EOF {
|
||||
t.Errorf("%v.Write(_, _, _) = %v, want <nil>", ct, err)
|
||||
}
|
||||
p := make([]byte, len(expectedResponseLarge))
|
||||
if _, err := io.ReadFull(s, p); err != nil || !bytes.Equal(p, expectedResponseLarge) {
|
||||
t.Errorf("io.ReadFull(_, %v) = _, %v, want %v, <nil>", err, p, expectedResponse)
|
||||
}
|
||||
if _, err = io.ReadFull(s, p); err != io.EOF {
|
||||
t.Errorf("Failed to complete the stream %v; want <EOF>", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestGracefulClose(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, normal)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Small",
|
||||
}
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("%v.NewStream(_, _) = _, %v, want _, <nil>", ct, err)
|
||||
}
|
||||
if err = ct.GracefulClose(); err != nil {
|
||||
t.Fatalf("%v.GracefulClose() = %v, want <nil>", ct, err)
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
// Expect the failure for all the follow-up streams because ct has been closed gracefully.
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if _, err := ct.NewStream(context.Background(), callHdr); err != ErrStreamDrain {
|
||||
t.Errorf("%v.NewStream(_, _) = _, %v, want _, %v", ct, err, ErrStreamDrain)
|
||||
}
|
||||
}()
|
||||
}
|
||||
opts := Options{
|
||||
Last: true,
|
||||
Delay: false,
|
||||
}
|
||||
// The stream which was created before graceful close can still proceed.
|
||||
if err := ct.Write(s, expectedRequest, &opts); err != nil && err != io.EOF {
|
||||
t.Fatalf("%v.Write(_, _, _) = %v, want <nil>", ct, err)
|
||||
}
|
||||
p := make([]byte, len(expectedResponse))
|
||||
if _, err := io.ReadFull(s, p); err != nil || !bytes.Equal(p, expectedResponse) {
|
||||
t.Fatalf("io.ReadFull(_, %v) = _, %v, want %v, <nil>", err, p, expectedResponse)
|
||||
}
|
||||
if _, err = io.ReadFull(s, p); err != io.EOF {
|
||||
t.Fatalf("Failed to complete the stream %v; want <EOF>", err)
|
||||
}
|
||||
wg.Wait()
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestLargeMessageSuspension(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, suspended)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Large",
|
||||
}
|
||||
// Set a long enough timeout for writing a large message out.
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Second)
|
||||
s, err := ct.NewStream(ctx, callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open stream: %v", err)
|
||||
}
|
||||
// Write should not be done successfully due to flow control.
|
||||
err = ct.Write(s, expectedRequestLarge, &Options{Last: true, Delay: false})
|
||||
expectedErr := streamErrorf(codes.DeadlineExceeded, "%v", context.DeadlineExceeded)
|
||||
if err != expectedErr {
|
||||
t.Fatalf("Write got %v, want %v", err, expectedErr)
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestMaxStreams(t *testing.T) {
|
||||
server, ct := setUp(t, 0, 1, suspended)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Large",
|
||||
}
|
||||
// Have a pending stream which takes all streams quota.
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open stream: %v", err)
|
||||
}
|
||||
cc, ok := ct.(*http2Client)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Client", ct)
|
||||
}
|
||||
done := make(chan struct{})
|
||||
ch := make(chan int)
|
||||
ready := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(5 * time.Millisecond):
|
||||
select {
|
||||
case ch <- 0:
|
||||
case <-ready:
|
||||
return
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
close(done)
|
||||
return
|
||||
case <-ready:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-ch:
|
||||
case <-done:
|
||||
t.Fatalf("Client has not received the max stream setting in 5 seconds.")
|
||||
}
|
||||
cc.mu.Lock()
|
||||
// cc.streamsQuota should be initialized once receiving the 1st setting frame from
|
||||
// the server.
|
||||
if cc.streamsQuota != nil {
|
||||
cc.mu.Unlock()
|
||||
select {
|
||||
case <-cc.streamsQuota.acquire():
|
||||
t.Fatalf("streamsQuota.acquire() becomes readable mistakenly.")
|
||||
default:
|
||||
if cc.streamsQuota.quota != 0 {
|
||||
t.Fatalf("streamsQuota.quota got non-zero quota mistakenly.")
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
cc.mu.Unlock()
|
||||
}
|
||||
close(ready)
|
||||
// Close the pending stream so that the streams quota becomes available for the next new stream.
|
||||
ct.CloseStream(s, nil)
|
||||
select {
|
||||
case i := <-cc.streamsQuota.acquire():
|
||||
if i != 1 {
|
||||
t.Fatalf("streamsQuota.acquire() got %d quota, want 1.", i)
|
||||
}
|
||||
cc.streamsQuota.add(i)
|
||||
default:
|
||||
t.Fatalf("streamsQuota.acquire() is not readable.")
|
||||
}
|
||||
if _, err := ct.NewStream(context.Background(), callHdr); err != nil {
|
||||
t.Fatalf("Failed to open stream: %v", err)
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestServerContextCanceledOnClosedConnection(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, suspended)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo",
|
||||
}
|
||||
var sc *http2Server
|
||||
// Wait until the server transport is setup.
|
||||
for {
|
||||
server.mu.Lock()
|
||||
if len(server.conns) == 0 {
|
||||
server.mu.Unlock()
|
||||
time.Sleep(time.Millisecond)
|
||||
continue
|
||||
}
|
||||
for k := range server.conns {
|
||||
var ok bool
|
||||
sc, ok = k.(*http2Server)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Server", k)
|
||||
}
|
||||
}
|
||||
server.mu.Unlock()
|
||||
break
|
||||
}
|
||||
cc, ok := ct.(*http2Client)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Client", ct)
|
||||
}
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open stream: %v", err)
|
||||
}
|
||||
// Make sure the headers frame is flushed out.
|
||||
<-cc.writableChan
|
||||
if err = cc.framer.writeData(true, s.id, false, make([]byte, http2MaxFrameLen)); err != nil {
|
||||
t.Fatalf("Failed to write data: %v", err)
|
||||
}
|
||||
cc.writableChan <- 0
|
||||
// Loop until the server side stream is created.
|
||||
var ss *Stream
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
sc.mu.Lock()
|
||||
if len(sc.activeStreams) == 0 {
|
||||
sc.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
ss = sc.activeStreams[s.id]
|
||||
sc.mu.Unlock()
|
||||
break
|
||||
}
|
||||
cc.Close()
|
||||
select {
|
||||
case <-ss.Context().Done():
|
||||
if ss.Context().Err() != context.Canceled {
|
||||
t.Fatalf("ss.Context().Err() got %v, want %v", ss.Context().Err(), context.Canceled)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("Failed to cancel the context of the sever side stream.")
|
||||
}
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestServerWithMisbehavedClient(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, suspended)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo",
|
||||
}
|
||||
var sc *http2Server
|
||||
// Wait until the server transport is setup.
|
||||
for {
|
||||
server.mu.Lock()
|
||||
if len(server.conns) == 0 {
|
||||
server.mu.Unlock()
|
||||
time.Sleep(time.Millisecond)
|
||||
continue
|
||||
}
|
||||
for k := range server.conns {
|
||||
var ok bool
|
||||
sc, ok = k.(*http2Server)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Server", k)
|
||||
}
|
||||
}
|
||||
server.mu.Unlock()
|
||||
break
|
||||
}
|
||||
cc, ok := ct.(*http2Client)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Client", ct)
|
||||
}
|
||||
// Test server behavior for violation of stream flow control window size restriction.
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open stream: %v", err)
|
||||
}
|
||||
var sent int
|
||||
// Drain the stream flow control window
|
||||
<-cc.writableChan
|
||||
if err = cc.framer.writeData(true, s.id, false, make([]byte, http2MaxFrameLen)); err != nil {
|
||||
t.Fatalf("Failed to write data: %v", err)
|
||||
}
|
||||
cc.writableChan <- 0
|
||||
sent += http2MaxFrameLen
|
||||
// Wait until the server creates the corresponding stream and receive some data.
|
||||
var ss *Stream
|
||||
for {
|
||||
time.Sleep(time.Millisecond)
|
||||
sc.mu.Lock()
|
||||
if len(sc.activeStreams) == 0 {
|
||||
sc.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
ss = sc.activeStreams[s.id]
|
||||
sc.mu.Unlock()
|
||||
ss.fc.mu.Lock()
|
||||
if ss.fc.pendingData > 0 {
|
||||
ss.fc.mu.Unlock()
|
||||
break
|
||||
}
|
||||
ss.fc.mu.Unlock()
|
||||
}
|
||||
if ss.fc.pendingData != http2MaxFrameLen || ss.fc.pendingUpdate != 0 || sc.fc.pendingData != http2MaxFrameLen || sc.fc.pendingUpdate != 0 {
|
||||
t.Fatalf("Server mistakenly updates inbound flow control params: got %d, %d, %d, %d; want %d, %d, %d, %d", ss.fc.pendingData, ss.fc.pendingUpdate, sc.fc.pendingData, sc.fc.pendingUpdate, http2MaxFrameLen, 0, http2MaxFrameLen, 0)
|
||||
}
|
||||
// Keep sending until the server inbound window is drained for that stream.
|
||||
for sent <= initialWindowSize {
|
||||
<-cc.writableChan
|
||||
if err = cc.framer.writeData(true, s.id, false, make([]byte, 1)); err != nil {
|
||||
t.Fatalf("Failed to write data: %v", err)
|
||||
}
|
||||
cc.writableChan <- 0
|
||||
sent++
|
||||
}
|
||||
// Server sent a resetStream for s already.
|
||||
code := http2ErrConvTab[http2.ErrCodeFlowControl]
|
||||
if _, err := io.ReadFull(s, make([]byte, 1)); err != io.EOF || s.statusCode != code {
|
||||
t.Fatalf("%v got err %v with statusCode %d, want err <EOF> with statusCode %d", s, err, s.statusCode, code)
|
||||
}
|
||||
|
||||
if ss.fc.pendingData != 0 || ss.fc.pendingUpdate != 0 || sc.fc.pendingData != 0 || sc.fc.pendingUpdate <= initialWindowSize {
|
||||
t.Fatalf("Server mistakenly resets inbound flow control params: got %d, %d, %d, %d; want 0, 0, 0, >%d", ss.fc.pendingData, ss.fc.pendingUpdate, sc.fc.pendingData, sc.fc.pendingUpdate, initialWindowSize)
|
||||
}
|
||||
ct.CloseStream(s, nil)
|
||||
// Test server behavior for violation of connection flow control window size restriction.
|
||||
//
|
||||
// Keep creating new streams until the connection window is drained on the server and
|
||||
// the server tears down the connection.
|
||||
for {
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
// The server tears down the connection.
|
||||
break
|
||||
}
|
||||
<-cc.writableChan
|
||||
cc.framer.writeData(true, s.id, true, make([]byte, http2MaxFrameLen))
|
||||
cc.writableChan <- 0
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestClientWithMisbehavedServer(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, misbehaved)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo.Stream",
|
||||
}
|
||||
conn, ok := ct.(*http2Client)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to convert %v to *http2Client", ct)
|
||||
}
|
||||
// Test the logic for the violation of stream flow control window size restriction.
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open stream: %v", err)
|
||||
}
|
||||
d := make([]byte, 1)
|
||||
if err := ct.Write(s, d, &Options{Last: true, Delay: false}); err != nil && err != io.EOF {
|
||||
t.Fatalf("Failed to write: %v", err)
|
||||
}
|
||||
// Read without window update.
|
||||
for {
|
||||
p := make([]byte, http2MaxFrameLen)
|
||||
if _, err = s.dec.Read(p); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if s.fc.pendingData <= initialWindowSize || s.fc.pendingUpdate != 0 || conn.fc.pendingData <= initialWindowSize || conn.fc.pendingUpdate != 0 {
|
||||
t.Fatalf("Client mistakenly updates inbound flow control params: got %d, %d, %d, %d; want >%d, %d, >%d, %d", s.fc.pendingData, s.fc.pendingUpdate, conn.fc.pendingData, conn.fc.pendingUpdate, initialWindowSize, 0, initialWindowSize, 0)
|
||||
}
|
||||
if err != io.EOF || s.statusCode != codes.Internal {
|
||||
t.Fatalf("Got err %v and the status code %d, want <EOF> and the code %d", err, s.statusCode, codes.Internal)
|
||||
}
|
||||
conn.CloseStream(s, err)
|
||||
if s.fc.pendingData != 0 || s.fc.pendingUpdate != 0 || conn.fc.pendingData != 0 || conn.fc.pendingUpdate <= initialWindowSize {
|
||||
t.Fatalf("Client mistakenly resets inbound flow control params: got %d, %d, %d, %d; want 0, 0, 0, >%d", s.fc.pendingData, s.fc.pendingUpdate, conn.fc.pendingData, conn.fc.pendingUpdate, initialWindowSize)
|
||||
}
|
||||
// Test the logic for the violation of the connection flow control window size restriction.
|
||||
//
|
||||
// Generate enough streams to drain the connection window. Make the server flood the traffic
|
||||
// to violate flow control window size of the connection.
|
||||
callHdr.Method = "foo.Connection"
|
||||
for i := 0; i < int(initialConnWindowSize/initialWindowSize+10); i++ {
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if err := ct.Write(s, d, &Options{Last: true, Delay: false}); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
// http2Client.errChan is closed due to connection flow control window size violation.
|
||||
<-conn.Error()
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
var (
|
||||
encodingTestStatusCode = codes.Internal
|
||||
encodingTestStatusDesc = "\n"
|
||||
)
|
||||
|
||||
func TestEncodingRequiredStatus(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, encodingRequiredStatus)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo",
|
||||
}
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
opts := Options{
|
||||
Last: true,
|
||||
Delay: false,
|
||||
}
|
||||
if err := ct.Write(s, expectedRequest, &opts); err != nil && err != io.EOF {
|
||||
t.Fatalf("Failed to write the request: %v", err)
|
||||
}
|
||||
p := make([]byte, http2MaxFrameLen)
|
||||
if _, err := s.dec.Read(p); err != io.EOF {
|
||||
t.Fatalf("Read got error %v, want %v", err, io.EOF)
|
||||
}
|
||||
if s.StatusCode() != encodingTestStatusCode || s.StatusDesc() != encodingTestStatusDesc {
|
||||
t.Fatalf("stream with status code %d, status desc %v, want %d, %v", s.StatusCode(), s.StatusDesc(), encodingTestStatusCode, encodingTestStatusDesc)
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestInvalidHeaderField(t *testing.T) {
|
||||
server, ct := setUp(t, 0, math.MaxUint32, invalidHeaderField)
|
||||
callHdr := &CallHdr{
|
||||
Host: "localhost",
|
||||
Method: "foo",
|
||||
}
|
||||
s, err := ct.NewStream(context.Background(), callHdr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
opts := Options{
|
||||
Last: true,
|
||||
Delay: false,
|
||||
}
|
||||
if err := ct.Write(s, expectedRequest, &opts); err != nil && err != io.EOF {
|
||||
t.Fatalf("Failed to write the request: %v", err)
|
||||
}
|
||||
p := make([]byte, http2MaxFrameLen)
|
||||
_, err = s.dec.Read(p)
|
||||
if se, ok := err.(StreamError); !ok || se.Code != codes.FailedPrecondition || !strings.Contains(err.Error(), expectedInvalidHeaderField) {
|
||||
t.Fatalf("Read got error %v, want error with code %s and contains %q", err, codes.FailedPrecondition, expectedInvalidHeaderField)
|
||||
}
|
||||
ct.Close()
|
||||
server.stop()
|
||||
}
|
||||
|
||||
func TestStreamContext(t *testing.T) {
|
||||
expectedStream := &Stream{}
|
||||
ctx := newContextWithStream(context.Background(), expectedStream)
|
||||
s, ok := StreamFromContext(ctx)
|
||||
if !ok || expectedStream != s {
|
||||
t.Fatalf("GetStreamFromContext(%v) = %v, %t, want: %v, true", ctx, s, ok, expectedStream)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsReservedHeader(t *testing.T) {
|
||||
tests := []struct {
|
||||
h string
|
||||
want bool
|
||||
}{
|
||||
{"", false}, // but should be rejected earlier
|
||||
{"foo", false},
|
||||
{"content-type", true},
|
||||
{"grpc-message-type", true},
|
||||
{"grpc-encoding", true},
|
||||
{"grpc-message", true},
|
||||
{"grpc-status", true},
|
||||
{"grpc-timeout", true},
|
||||
{"te", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := isReservedHeader(tt.h)
|
||||
if got != tt.want {
|
||||
t.Errorf("isReservedHeader(%q) = %v; want %v", tt.h, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user