mirror of
https://github.com/restic/restic.git
synced 2025-10-26 19:19:50 +00:00
Update dependencies
Among others, this updates minio-go, so that the new "eu-west-3" zone for AWS is supported.
This commit is contained in:
54
vendor/cloud.google.com/go/internal/annotate.go
generated
vendored
Normal file
54
vendor/cloud.google.com/go/internal/annotate.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Annotate prepends msg to the error message in err, attempting
|
||||
// to preserve other information in err, like an error code.
|
||||
//
|
||||
// Annotate panics if err is nil.
|
||||
//
|
||||
// Annotate knows about these error types:
|
||||
// - "google.golang.org/grpc/status".Status
|
||||
// - "google.golang.org/api/googleapi".Error
|
||||
// If the error is not one of these types, Annotate behaves
|
||||
// like
|
||||
// fmt.Errorf("%s: %v", msg, err)
|
||||
func Annotate(err error, msg string) error {
|
||||
if err == nil {
|
||||
panic("Annotate called with nil")
|
||||
}
|
||||
if s, ok := status.FromError(err); ok {
|
||||
p := s.Proto()
|
||||
p.Message = msg + ": " + p.Message
|
||||
return status.ErrorProto(p)
|
||||
}
|
||||
if g, ok := err.(*googleapi.Error); ok {
|
||||
g.Message = msg + ": " + g.Message
|
||||
return g
|
||||
}
|
||||
return fmt.Errorf("%s: %v", msg, err)
|
||||
}
|
||||
|
||||
// Annotatef uses format and args to format a string, then calls Annotate.
|
||||
func Annotatef(err error, format string, args ...interface{}) error {
|
||||
return Annotate(err, fmt.Sprintf(format, args...))
|
||||
}
|
||||
65
vendor/cloud.google.com/go/internal/annotate_test.go
generated
vendored
Normal file
65
vendor/cloud.google.com/go/internal/annotate_test.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const wantMessage = "prefix: msg"
|
||||
|
||||
func TestAnnotateGRPC(t *testing.T) {
|
||||
// grpc Status error
|
||||
err := status.Error(codes.NotFound, "msg")
|
||||
err = Annotate(err, "prefix")
|
||||
got, ok := status.FromError(err)
|
||||
if !ok {
|
||||
t.Fatalf("got %T, wanted a status", got)
|
||||
}
|
||||
if g, w := got.Code(), codes.NotFound; g != w {
|
||||
t.Errorf("got code %v, want %v", g, w)
|
||||
}
|
||||
if g, w := got.Message(), wantMessage; g != w {
|
||||
t.Errorf("got message %q, want %q", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateGoogleapi(t *testing.T) {
|
||||
// googleapi error
|
||||
var err error = &googleapi.Error{Code: 403, Message: "msg"}
|
||||
err = Annotate(err, "prefix")
|
||||
got2, ok := err.(*googleapi.Error)
|
||||
if !ok {
|
||||
t.Fatalf("got %T, wanted a googleapi.Error", got2)
|
||||
}
|
||||
if g, w := got2.Code, 403; g != w {
|
||||
t.Errorf("got code %d, want %d", g, w)
|
||||
}
|
||||
if g, w := got2.Message, wantMessage; g != w {
|
||||
t.Errorf("got message %q, want %q", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateUnknownError(t *testing.T) {
|
||||
err := Annotate(errors.New("msg"), "prefix")
|
||||
if g, w := err.Error(), wantMessage; g != w {
|
||||
t.Errorf("got message %q, want %q", g, w)
|
||||
}
|
||||
}
|
||||
24
vendor/cloud.google.com/go/internal/fields/fields.go
generated
vendored
24
vendor/cloud.google.com/go/internal/fields/fields.go
generated
vendored
@@ -65,8 +65,10 @@ package fields
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/internal/atomiccache"
|
||||
)
|
||||
@@ -442,3 +444,25 @@ func dominantField(fs []Field) (Field, bool) {
|
||||
}
|
||||
return fs[0], true
|
||||
}
|
||||
|
||||
// ParseStandardTag extracts the sub-tag named by key, then parses it using the
|
||||
// de facto standard format introduced in encoding/json:
|
||||
// "-" means "ignore this tag". It must occur by itself. (parseStandardTag returns an error
|
||||
// in this case, whereas encoding/json accepts the "-" even if it is not alone.)
|
||||
// "<name>" provides an alternative name for the field
|
||||
// "<name>,opt1,opt2,..." specifies options after the name.
|
||||
// The options are returned as a []string.
|
||||
func ParseStandardTag(key string, t reflect.StructTag) (name string, keep bool, options []string, err error) {
|
||||
s := t.Get(key)
|
||||
parts := strings.Split(s, ",")
|
||||
if parts[0] == "-" {
|
||||
if len(parts) > 1 {
|
||||
return "", false, nil, errors.New(`"-" field tag with options`)
|
||||
}
|
||||
return "", false, nil, nil
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
options = parts[1:]
|
||||
}
|
||||
return parts[0], true, options, nil
|
||||
}
|
||||
|
||||
27
vendor/cloud.google.com/go/internal/fields/fields_test.go
generated
vendored
27
vendor/cloud.google.com/go/internal/fields/fields_test.go
generated
vendored
@@ -19,7 +19,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -75,9 +74,10 @@ var intType = reflect.TypeOf(int(0))
|
||||
|
||||
func field(name string, tval interface{}, index ...int) *Field {
|
||||
return &Field{
|
||||
Name: name,
|
||||
Type: reflect.TypeOf(tval),
|
||||
Index: index,
|
||||
Name: name,
|
||||
Type: reflect.TypeOf(tval),
|
||||
Index: index,
|
||||
ParsedTag: []string(nil),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ func tfield(name string, tval interface{}, index ...int) *Field {
|
||||
Type: reflect.TypeOf(tval),
|
||||
Index: index,
|
||||
NameFromTag: true,
|
||||
ParsedTag: []string(nil),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +104,9 @@ func TestFieldsNoTags(t *testing.T) {
|
||||
field("Em4", int(0), 4, 2, 0),
|
||||
field("Anonymous", Anonymous(0), 5),
|
||||
}
|
||||
for _, f := range want {
|
||||
f.ParsedTag = nil
|
||||
}
|
||||
if msg, ok := compareFields(got, want); !ok {
|
||||
t.Error(msg)
|
||||
}
|
||||
@@ -138,9 +142,10 @@ func TestAgainstJSONEncodingNoTags(t *testing.T) {
|
||||
Anonymous: Anonymous(15),
|
||||
}
|
||||
var want S1
|
||||
want.embed2 = &embed2{} // need this because reflection won't create it
|
||||
jsonRoundTrip(t, s1, &want)
|
||||
var got S1
|
||||
got.embed2 = &embed2{} // need this because reflection won't create it
|
||||
got.embed2 = &embed2{}
|
||||
fields, err := NewCache(nil, nil, nil).Fields(reflect.TypeOf(got))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -204,15 +209,7 @@ type tEmbed2 struct {
|
||||
}
|
||||
|
||||
func jsonTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) {
|
||||
s := t.Get("json")
|
||||
parts := strings.Split(s, ",")
|
||||
if parts[0] == "-" {
|
||||
return "", false, nil, nil
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
other = parts[1:]
|
||||
}
|
||||
return parts[0], true, other, nil
|
||||
return ParseStandardTag("json", t)
|
||||
}
|
||||
|
||||
func validateFunc(t reflect.Type) (err error) {
|
||||
@@ -408,7 +405,7 @@ func compareFields(got []Field, want []*Field) (msg string, ok bool) {
|
||||
for i, g := range got {
|
||||
w := *want[i]
|
||||
if !fieldsEqual(&g, &w) {
|
||||
return fmt.Sprintf("got %+v, want %+v", g, w), false
|
||||
return fmt.Sprintf("got\n%+v\nwant\n%+v", g, w), false
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
|
||||
56
vendor/cloud.google.com/go/internal/protostruct/protostruct.go
generated
vendored
Normal file
56
vendor/cloud.google.com/go/internal/protostruct/protostruct.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package protostruct supports operations on the protocol buffer Struct message.
|
||||
package protostruct
|
||||
|
||||
import (
|
||||
pb "github.com/golang/protobuf/ptypes/struct"
|
||||
)
|
||||
|
||||
// DecodeToMap converts a pb.Struct to a map from strings to Go types.
|
||||
// DecodeToMap panics if s is invalid.
|
||||
func DecodeToMap(s *pb.Struct) map[string]interface{} {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
m := map[string]interface{}{}
|
||||
for k, v := range s.Fields {
|
||||
m[k] = decodeValue(v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func decodeValue(v *pb.Value) interface{} {
|
||||
switch k := v.Kind.(type) {
|
||||
case *pb.Value_NullValue:
|
||||
return nil
|
||||
case *pb.Value_NumberValue:
|
||||
return k.NumberValue
|
||||
case *pb.Value_StringValue:
|
||||
return k.StringValue
|
||||
case *pb.Value_BoolValue:
|
||||
return k.BoolValue
|
||||
case *pb.Value_StructValue:
|
||||
return DecodeToMap(k.StructValue)
|
||||
case *pb.Value_ListValue:
|
||||
s := make([]interface{}, len(k.ListValue.Values))
|
||||
for i, e := range k.ListValue.Values {
|
||||
s[i] = decodeValue(e)
|
||||
}
|
||||
return s
|
||||
default:
|
||||
panic("protostruct: unknown kind")
|
||||
}
|
||||
}
|
||||
58
vendor/cloud.google.com/go/internal/protostruct/protostruct_test.go
generated
vendored
Normal file
58
vendor/cloud.google.com/go/internal/protostruct/protostruct_test.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package protostruct supports operations on the protocol buffer Struct message.
|
||||
package protostruct
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"cloud.google.com/go/internal/testutil"
|
||||
pb "github.com/golang/protobuf/ptypes/struct"
|
||||
)
|
||||
|
||||
func TestDecodeToMap(t *testing.T) {
|
||||
if got := DecodeToMap(nil); !testutil.Equal(got, map[string]interface{}(nil)) {
|
||||
t.Errorf("DecodeToMap(nil) = %v, want nil", got)
|
||||
}
|
||||
nullv := &pb.Value{&pb.Value_NullValue{}}
|
||||
stringv := &pb.Value{&pb.Value_StringValue{"x"}}
|
||||
boolv := &pb.Value{&pb.Value_BoolValue{true}}
|
||||
numberv := &pb.Value{&pb.Value_NumberValue{2.7}}
|
||||
in := &pb.Struct{Fields: map[string]*pb.Value{
|
||||
"n": nullv,
|
||||
"s": stringv,
|
||||
"b": boolv,
|
||||
"f": numberv,
|
||||
"l": &pb.Value{&pb.Value_ListValue{&pb.ListValue{
|
||||
[]*pb.Value{nullv, stringv, boolv, numberv},
|
||||
}}},
|
||||
"S": &pb.Value{&pb.Value_StructValue{&pb.Struct{Fields: map[string]*pb.Value{
|
||||
"n1": nullv,
|
||||
"b1": boolv,
|
||||
}}}},
|
||||
}}
|
||||
want := map[string]interface{}{
|
||||
"n": nil,
|
||||
"s": "x",
|
||||
"b": true,
|
||||
"f": 2.7,
|
||||
"l": []interface{}{nil, "x", true, 2.7},
|
||||
"S": map[string]interface{}{"n1": nil, "b1": true},
|
||||
}
|
||||
got := DecodeToMap(in)
|
||||
if diff := testutil.Diff(got, want); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
3
vendor/cloud.google.com/go/internal/retry.go
generated
vendored
3
vendor/cloud.google.com/go/internal/retry.go
generated
vendored
@@ -15,7 +15,6 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
@@ -48,7 +47,7 @@ func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
|
||||
p := bo.Pause()
|
||||
if cerr := sleep(ctx, p); cerr != nil {
|
||||
if lastErr != nil {
|
||||
return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
|
||||
return Annotatef(lastErr, "retry failed with %v; last error", cerr)
|
||||
}
|
||||
return cerr
|
||||
}
|
||||
|
||||
29
vendor/cloud.google.com/go/internal/retry_test.go
generated
vendored
29
vendor/cloud.google.com/go/internal/retry_test.go
generated
vendored
@@ -16,12 +16,14 @@ package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestRetry(t *testing.T) {
|
||||
@@ -62,3 +64,26 @@ func TestRetry(t *testing.T) {
|
||||
t.Error("got nil, want error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryPreserveError(t *testing.T) {
|
||||
// Retry tries to preserve the type and other information from
|
||||
// the last error returned by the function.
|
||||
err := retry(context.Background(), gax.Backoff{},
|
||||
func() (bool, error) {
|
||||
return false, status.Error(codes.NotFound, "not found")
|
||||
},
|
||||
func(context.Context, time.Duration) error {
|
||||
return context.DeadlineExceeded
|
||||
})
|
||||
got, ok := status.FromError(err)
|
||||
if !ok {
|
||||
t.Fatalf("got %T, wanted a status", got)
|
||||
}
|
||||
if g, w := got.Code(), codes.NotFound; g != w {
|
||||
t.Errorf("got code %v, want %v", g, w)
|
||||
}
|
||||
wantMessage := fmt.Sprintf("retry failed with %v; last error: not found", context.DeadlineExceeded)
|
||||
if g, w := got.Message(), wantMessage; g != w {
|
||||
t.Errorf("got message %q, want %q", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
32
vendor/cloud.google.com/go/internal/rpcreplay/Makefile
generated
vendored
32
vendor/cloud.google.com/go/internal/rpcreplay/Makefile
generated
vendored
@@ -1,32 +0,0 @@
|
||||
# Copyright 2017 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Makefile for building Go files from protos.
|
||||
|
||||
# Change these to match your environment.
|
||||
PROTOC=$(HOME)/bin/protoc
|
||||
PROTOC_GO_PLUGIN_DIR=$(GOPATH)/bin
|
||||
PROTOBUF_REPO=$(HOME)/git-repos/protobuf
|
||||
|
||||
gen-protos: sync-protobuf
|
||||
for d in proto/*; do \
|
||||
PATH=$(PATH):$(PROTOC_GO_PLUGIN_DIR) \
|
||||
$(PROTOC) --go_out=plugins=grpc:$$d \
|
||||
-I $$d -I $(PROTOBUF_REPO)/src $$d/*.proto; \
|
||||
done
|
||||
|
||||
|
||||
sync-protobuf:
|
||||
cd $(PROTOBUF_REPO); git pull
|
||||
|
||||
106
vendor/cloud.google.com/go/internal/rpcreplay/doc.go
generated
vendored
106
vendor/cloud.google.com/go/internal/rpcreplay/doc.go
generated
vendored
@@ -1,106 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
Package rpcreplay supports the capture and replay of gRPC calls. Its main goal is
|
||||
to improve testing. Once one captures the calls of a test that runs against a real
|
||||
service, one has an "automatic mock" that can be replayed against the same test,
|
||||
yielding a unit test that is fast and flake-free.
|
||||
|
||||
|
||||
Recording
|
||||
|
||||
To record a sequence of gRPC calls to a file, create a Recorder and pass its
|
||||
DialOptions to grpc.Dial:
|
||||
|
||||
rec, err := rpcreplay.NewRecorder("service.replay", nil)
|
||||
if err != nil { ... }
|
||||
defer func() {
|
||||
if err := rec.Close(); err != nil { ... }
|
||||
}()
|
||||
conn, err := grpc.Dial(serverAddress, rec.DialOptions()...)
|
||||
|
||||
It's essential to close the Recorder when the interaction is finished.
|
||||
|
||||
There is also a NewRecorderWriter function for capturing to an arbitrary
|
||||
io.Writer.
|
||||
|
||||
|
||||
Replaying
|
||||
|
||||
Replaying a captured file looks almost identical: create a Replayer and use
|
||||
its DialOptions. (Since we're reading the file and not writing it, we don't
|
||||
have to be as careful about the error returned from Close).
|
||||
|
||||
rep, err := rpcreplay.NewReplayer("service.replay")
|
||||
if err != nil { ... }
|
||||
defer rep.Close()
|
||||
conn, err := grpc.Dial(serverAddress, rep.DialOptions()...)
|
||||
|
||||
|
||||
Initial State
|
||||
|
||||
A test might use random or time-sensitive values, for instance to create unique
|
||||
resources for isolation from other tests. The test therefore has initial values --
|
||||
the current time, a random seed -- that differ from run to run. You must record this
|
||||
initial state and re-establish it on replay.
|
||||
|
||||
To record the initial state, serialize it into a []byte and pass it as the second
|
||||
argument to NewRecorder:
|
||||
|
||||
timeNow := time.Now()
|
||||
b, err := timeNow.MarshalBinary()
|
||||
if err != nil { ... }
|
||||
rec, err := rpcreplay.NewRecorder("service.replay", b)
|
||||
|
||||
On replay, get the bytes from Replayer.Initial:
|
||||
|
||||
rep, err := rpcreplay.NewReplayer("service.replay")
|
||||
if err != nil { ... }
|
||||
defer rep.Close()
|
||||
err = timeNow.UnmarshalBinary(rep.Initial())
|
||||
if err != nil { ... }
|
||||
|
||||
|
||||
Nondeterminism
|
||||
|
||||
A nondeterministic program may invoke RPCs in a different order each time
|
||||
it is run. The order in which RPCs are called during recording may differ
|
||||
from the order during replay.
|
||||
|
||||
The replayer matches incoming to recorded requests by method name and request
|
||||
contents, so nondeterminism is only a concern for identical requests that result
|
||||
in different responses. A nondeterministic program whose behavior differs
|
||||
depending on the order of such RPCs probably has a race condition: since both the
|
||||
recorded sequence of RPCs and the sequence during replay are valid orderings, the
|
||||
program should behave the same under both.
|
||||
|
||||
|
||||
Other Replayer Differences
|
||||
|
||||
Besides the differences in replay mentioned above, other differences may cause issues
|
||||
for some programs. We list them here.
|
||||
|
||||
The Replayer delivers a response to an RPC immediately, without waiting for other
|
||||
incoming RPCs. This can violate causality. For example, in a Pub/Sub program where
|
||||
one goroutine publishes and another subscribes, during replay the Subscribe call may
|
||||
finish before the Publish call begins.
|
||||
|
||||
For streaming RPCs, the Replayer delivers the result of Send and Recv calls in
|
||||
the order they were recorded. No attempt is made to match message contents.
|
||||
|
||||
At present, this package does not record or replay stream headers and trailers, or
|
||||
the result of the CloseSend method.
|
||||
*/
|
||||
package rpcreplay // import "cloud.google.com/go/internal/rpcreplay"
|
||||
47
vendor/cloud.google.com/go/internal/rpcreplay/example_test.go
generated
vendored
47
vendor/cloud.google.com/go/internal/rpcreplay/example_test.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rpcreplay_test
|
||||
|
||||
var serverAddress string
|
||||
|
||||
// func Example_NewRecorder() {
|
||||
// rec, err := rpcreplay.NewRecorder("service.replay", nil)
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// defer func() {
|
||||
// if err := rec.Close(); err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// }()
|
||||
// conn, err := grpc.Dial(serverAddress, rec.DialOptions()...)
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// _ = conn // TODO: use connection
|
||||
// }
|
||||
|
||||
// func Example_NewReplayer() {
|
||||
// rep, err := rpcreplay.NewReplayer("service.replay")
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// defer rep.Close()
|
||||
// conn, err := grpc.Dial(serverAddress, rep.DialOptions()...)
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// _ = conn // TODO: use connection
|
||||
// }
|
||||
121
vendor/cloud.google.com/go/internal/rpcreplay/fake_test.go
generated
vendored
121
vendor/cloud.google.com/go/internal/rpcreplay/fake_test.go
generated
vendored
@@ -1,121 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rpcreplay
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
pb "cloud.google.com/go/internal/rpcreplay/proto/intstore"
|
||||
)
|
||||
|
||||
// intStoreServer is an in-memory implementation of IntStore.
|
||||
type intStoreServer struct {
|
||||
pb.IntStoreServer
|
||||
|
||||
Addr string
|
||||
l net.Listener
|
||||
gsrv *grpc.Server
|
||||
|
||||
items map[string]int32
|
||||
}
|
||||
|
||||
func newIntStoreServer() *intStoreServer {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s := &intStoreServer{
|
||||
Addr: l.Addr().String(),
|
||||
l: l,
|
||||
gsrv: grpc.NewServer(),
|
||||
}
|
||||
pb.RegisterIntStoreServer(s.gsrv, s)
|
||||
go s.gsrv.Serve(s.l)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *intStoreServer) stop() {
|
||||
s.gsrv.Stop()
|
||||
s.l.Close()
|
||||
}
|
||||
|
||||
func (s *intStoreServer) Set(_ context.Context, item *pb.Item) (*pb.SetResponse, error) {
|
||||
old := s.setItem(item)
|
||||
return &pb.SetResponse{PrevValue: old}, nil
|
||||
}
|
||||
|
||||
func (s *intStoreServer) setItem(item *pb.Item) int32 {
|
||||
if s.items == nil {
|
||||
s.items = map[string]int32{}
|
||||
}
|
||||
old := s.items[item.Name]
|
||||
s.items[item.Name] = item.Value
|
||||
return old
|
||||
}
|
||||
|
||||
func (s *intStoreServer) Get(_ context.Context, req *pb.GetRequest) (*pb.Item, error) {
|
||||
val, ok := s.items[req.Name]
|
||||
if !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "%q", req.Name)
|
||||
}
|
||||
return &pb.Item{Name: req.Name, Value: val}, nil
|
||||
}
|
||||
|
||||
func (s *intStoreServer) ListItems(_ *pb.ListItemsRequest, ss pb.IntStore_ListItemsServer) error {
|
||||
for name, val := range s.items {
|
||||
if err := ss.Send(&pb.Item{Name: name, Value: val}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *intStoreServer) SetStream(ss pb.IntStore_SetStreamServer) error {
|
||||
n := 0
|
||||
for {
|
||||
item, err := ss.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.setItem(item)
|
||||
n++
|
||||
}
|
||||
return ss.SendAndClose(&pb.Summary{Count: int32(n)})
|
||||
}
|
||||
|
||||
func (s *intStoreServer) StreamChat(ss pb.IntStore_StreamChatServer) error {
|
||||
for {
|
||||
item, err := ss.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ss.Send(item); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
454
vendor/cloud.google.com/go/internal/rpcreplay/proto/intstore/intstore.pb.go
generated
vendored
454
vendor/cloud.google.com/go/internal/rpcreplay/proto/intstore/intstore.pb.go
generated
vendored
@@ -1,454 +0,0 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: intstore.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package intstore is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
intstore.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Item
|
||||
SetResponse
|
||||
GetRequest
|
||||
Summary
|
||||
ListItemsRequest
|
||||
*/
|
||||
package intstore
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Item struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||
Value int32 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Item) Reset() { *m = Item{} }
|
||||
func (m *Item) String() string { return proto.CompactTextString(m) }
|
||||
func (*Item) ProtoMessage() {}
|
||||
func (*Item) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *Item) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Item) GetValue() int32 {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type SetResponse struct {
|
||||
PrevValue int32 `protobuf:"varint,1,opt,name=prev_value,json=prevValue" json:"prev_value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SetResponse) Reset() { *m = SetResponse{} }
|
||||
func (m *SetResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SetResponse) ProtoMessage() {}
|
||||
func (*SetResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
func (m *SetResponse) GetPrevValue() int32 {
|
||||
if m != nil {
|
||||
return m.PrevValue
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetRequest struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (m *GetRequest) Reset() { *m = GetRequest{} }
|
||||
func (m *GetRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetRequest) ProtoMessage() {}
|
||||
func (*GetRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
func (m *GetRequest) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Summary struct {
|
||||
Count int32 `protobuf:"varint,1,opt,name=count" json:"count,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Summary) Reset() { *m = Summary{} }
|
||||
func (m *Summary) String() string { return proto.CompactTextString(m) }
|
||||
func (*Summary) ProtoMessage() {}
|
||||
func (*Summary) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func (m *Summary) GetCount() int32 {
|
||||
if m != nil {
|
||||
return m.Count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ListItemsRequest struct {
|
||||
}
|
||||
|
||||
func (m *ListItemsRequest) Reset() { *m = ListItemsRequest{} }
|
||||
func (m *ListItemsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListItemsRequest) ProtoMessage() {}
|
||||
func (*ListItemsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Item)(nil), "intstore.Item")
|
||||
proto.RegisterType((*SetResponse)(nil), "intstore.SetResponse")
|
||||
proto.RegisterType((*GetRequest)(nil), "intstore.GetRequest")
|
||||
proto.RegisterType((*Summary)(nil), "intstore.Summary")
|
||||
proto.RegisterType((*ListItemsRequest)(nil), "intstore.ListItemsRequest")
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// Client API for IntStore service
|
||||
|
||||
type IntStoreClient interface {
|
||||
Set(ctx context.Context, in *Item, opts ...grpc.CallOption) (*SetResponse, error)
|
||||
Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*Item, error)
|
||||
// A server-to-client streaming RPC.
|
||||
ListItems(ctx context.Context, in *ListItemsRequest, opts ...grpc.CallOption) (IntStore_ListItemsClient, error)
|
||||
// A client-to-server streaming RPC.
|
||||
SetStream(ctx context.Context, opts ...grpc.CallOption) (IntStore_SetStreamClient, error)
|
||||
// A Bidirectional streaming RPC.
|
||||
StreamChat(ctx context.Context, opts ...grpc.CallOption) (IntStore_StreamChatClient, error)
|
||||
}
|
||||
|
||||
type intStoreClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewIntStoreClient(cc *grpc.ClientConn) IntStoreClient {
|
||||
return &intStoreClient{cc}
|
||||
}
|
||||
|
||||
func (c *intStoreClient) Set(ctx context.Context, in *Item, opts ...grpc.CallOption) (*SetResponse, error) {
|
||||
out := new(SetResponse)
|
||||
err := grpc.Invoke(ctx, "/intstore.IntStore/Set", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *intStoreClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*Item, error) {
|
||||
out := new(Item)
|
||||
err := grpc.Invoke(ctx, "/intstore.IntStore/Get", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *intStoreClient) ListItems(ctx context.Context, in *ListItemsRequest, opts ...grpc.CallOption) (IntStore_ListItemsClient, error) {
|
||||
stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[0], c.cc, "/intstore.IntStore/ListItems", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &intStoreListItemsClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type IntStore_ListItemsClient interface {
|
||||
Recv() (*Item, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type intStoreListItemsClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *intStoreListItemsClient) Recv() (*Item, error) {
|
||||
m := new(Item)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *intStoreClient) SetStream(ctx context.Context, opts ...grpc.CallOption) (IntStore_SetStreamClient, error) {
|
||||
stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[1], c.cc, "/intstore.IntStore/SetStream", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &intStoreSetStreamClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type IntStore_SetStreamClient interface {
|
||||
Send(*Item) error
|
||||
CloseAndRecv() (*Summary, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type intStoreSetStreamClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *intStoreSetStreamClient) Send(m *Item) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *intStoreSetStreamClient) CloseAndRecv() (*Summary, error) {
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := new(Summary)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *intStoreClient) StreamChat(ctx context.Context, opts ...grpc.CallOption) (IntStore_StreamChatClient, error) {
|
||||
stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[2], c.cc, "/intstore.IntStore/StreamChat", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &intStoreStreamChatClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type IntStore_StreamChatClient interface {
|
||||
Send(*Item) error
|
||||
Recv() (*Item, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type intStoreStreamChatClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *intStoreStreamChatClient) Send(m *Item) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *intStoreStreamChatClient) Recv() (*Item, error) {
|
||||
m := new(Item)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Server API for IntStore service
|
||||
|
||||
type IntStoreServer interface {
|
||||
Set(context.Context, *Item) (*SetResponse, error)
|
||||
Get(context.Context, *GetRequest) (*Item, error)
|
||||
// A server-to-client streaming RPC.
|
||||
ListItems(*ListItemsRequest, IntStore_ListItemsServer) error
|
||||
// A client-to-server streaming RPC.
|
||||
SetStream(IntStore_SetStreamServer) error
|
||||
// A Bidirectional streaming RPC.
|
||||
StreamChat(IntStore_StreamChatServer) error
|
||||
}
|
||||
|
||||
func RegisterIntStoreServer(s *grpc.Server, srv IntStoreServer) {
|
||||
s.RegisterService(&_IntStore_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _IntStore_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Item)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(IntStoreServer).Set(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/intstore.IntStore/Set",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(IntStoreServer).Set(ctx, req.(*Item))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _IntStore_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(IntStoreServer).Get(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/intstore.IntStore/Get",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(IntStoreServer).Get(ctx, req.(*GetRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _IntStore_ListItems_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(ListItemsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(IntStoreServer).ListItems(m, &intStoreListItemsServer{stream})
|
||||
}
|
||||
|
||||
type IntStore_ListItemsServer interface {
|
||||
Send(*Item) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type intStoreListItemsServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *intStoreListItemsServer) Send(m *Item) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _IntStore_SetStream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(IntStoreServer).SetStream(&intStoreSetStreamServer{stream})
|
||||
}
|
||||
|
||||
type IntStore_SetStreamServer interface {
|
||||
SendAndClose(*Summary) error
|
||||
Recv() (*Item, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type intStoreSetStreamServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *intStoreSetStreamServer) SendAndClose(m *Summary) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *intStoreSetStreamServer) Recv() (*Item, error) {
|
||||
m := new(Item)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func _IntStore_StreamChat_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(IntStoreServer).StreamChat(&intStoreStreamChatServer{stream})
|
||||
}
|
||||
|
||||
type IntStore_StreamChatServer interface {
|
||||
Send(*Item) error
|
||||
Recv() (*Item, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type intStoreStreamChatServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *intStoreStreamChatServer) Send(m *Item) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *intStoreStreamChatServer) Recv() (*Item, error) {
|
||||
m := new(Item)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var _IntStore_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "intstore.IntStore",
|
||||
HandlerType: (*IntStoreServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Set",
|
||||
Handler: _IntStore_Set_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Get",
|
||||
Handler: _IntStore_Get_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "ListItems",
|
||||
Handler: _IntStore_ListItems_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "SetStream",
|
||||
Handler: _IntStore_SetStream_Handler,
|
||||
ClientStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "StreamChat",
|
||||
Handler: _IntStore_StreamChat_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "intstore.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("intstore.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 273 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4b, 0xc3, 0x40,
|
||||
0x10, 0xc5, 0xb3, 0xfd, 0xa3, 0xcd, 0x08, 0x45, 0x87, 0x0a, 0x25, 0x20, 0x86, 0x3d, 0xe5, 0xa0,
|
||||
0x21, 0xd4, 0xa3, 0x47, 0x0f, 0xa5, 0xe0, 0x29, 0x0b, 0x5e, 0x25, 0xca, 0x80, 0x05, 0xb3, 0x1b,
|
||||
0x77, 0x27, 0x05, 0xbf, 0x84, 0x9f, 0x59, 0x36, 0x5b, 0x9b, 0xd2, 0x78, 0xdb, 0xb7, 0xf3, 0x66,
|
||||
0xde, 0x6f, 0x76, 0x61, 0xbe, 0xd5, 0xec, 0xd8, 0x58, 0xca, 0x1b, 0x6b, 0xd8, 0xe0, 0xec, 0x4f,
|
||||
0xcb, 0x02, 0x26, 0x1b, 0xa6, 0x1a, 0x11, 0x26, 0xba, 0xaa, 0x69, 0x29, 0x52, 0x91, 0xc5, 0x65,
|
||||
0x77, 0xc6, 0x05, 0x4c, 0x77, 0xd5, 0x67, 0x4b, 0xcb, 0x51, 0x2a, 0xb2, 0x69, 0x19, 0x84, 0xbc,
|
||||
0x83, 0x0b, 0x45, 0x5c, 0x92, 0x6b, 0x8c, 0x76, 0x84, 0x37, 0x00, 0x8d, 0xa5, 0xdd, 0x6b, 0x70,
|
||||
0x8a, 0xce, 0x19, 0xfb, 0x9b, 0x97, 0xce, 0x9d, 0x02, 0xac, 0xbd, 0xfb, 0xab, 0x25, 0xc7, 0xff,
|
||||
0xa5, 0xc8, 0x5b, 0x38, 0x57, 0x6d, 0x5d, 0x57, 0xf6, 0xdb, 0x07, 0xbe, 0x9b, 0x56, 0xf3, 0x7e,
|
||||
0x4c, 0x10, 0x12, 0xe1, 0xf2, 0x79, 0xeb, 0xd8, 0x63, 0xba, 0xfd, 0xa0, 0xd5, 0xcf, 0x08, 0x66,
|
||||
0x1b, 0xcd, 0xca, 0xef, 0x80, 0x39, 0x8c, 0x15, 0x31, 0xce, 0xf3, 0xc3, 0x96, 0xde, 0x9b, 0x5c,
|
||||
0xf7, 0xfa, 0x08, 0x58, 0x46, 0x78, 0x0f, 0xe3, 0x35, 0x31, 0x2e, 0xfa, 0x7a, 0x8f, 0x98, 0x9c,
|
||||
0x4c, 0x91, 0x11, 0x3e, 0x42, 0x7c, 0xc8, 0xc7, 0xa4, 0x2f, 0x9f, 0x42, 0x0d, 0x5b, 0x0b, 0x81,
|
||||
0x2b, 0x88, 0x15, 0xb1, 0x62, 0x4b, 0x55, 0x3d, 0x20, 0xbc, 0x3a, 0x22, 0x0c, 0x4f, 0x20, 0xa3,
|
||||
0xcc, 0xf7, 0x40, 0x68, 0x78, 0xfa, 0xa8, 0x86, 0x6b, 0x0d, 0x52, 0x32, 0x51, 0x88, 0xb7, 0xb3,
|
||||
0xee, 0x63, 0x1f, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x22, 0x28, 0xa0, 0x49, 0xea, 0x01, 0x00,
|
||||
0x00,
|
||||
}
|
||||
54
vendor/cloud.google.com/go/internal/rpcreplay/proto/intstore/intstore.proto
generated
vendored
54
vendor/cloud.google.com/go/internal/rpcreplay/proto/intstore/intstore.proto
generated
vendored
@@ -1,54 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// IntStore is a service for testing the rpcreplay package.
|
||||
// It is a simple key-value store for integers.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package intstore;
|
||||
|
||||
service IntStore {
|
||||
rpc Set(Item) returns (SetResponse) {}
|
||||
|
||||
rpc Get(GetRequest) returns (Item) {}
|
||||
|
||||
// A server-to-client streaming RPC.
|
||||
rpc ListItems(ListItemsRequest) returns (stream Item) {}
|
||||
|
||||
// A client-to-server streaming RPC.
|
||||
rpc SetStream(stream Item) returns (Summary) {}
|
||||
|
||||
// A Bidirectional streaming RPC.
|
||||
rpc StreamChat(stream Item) returns (stream Item) {}
|
||||
}
|
||||
|
||||
message Item {
|
||||
string name = 1;
|
||||
int32 value = 2;
|
||||
}
|
||||
|
||||
message SetResponse {
|
||||
int32 prev_value = 1;
|
||||
}
|
||||
|
||||
message GetRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message Summary {
|
||||
int32 count = 1;
|
||||
}
|
||||
|
||||
message ListItemsRequest {}
|
||||
170
vendor/cloud.google.com/go/internal/rpcreplay/proto/rpcreplay/rpcreplay.pb.go
generated
vendored
170
vendor/cloud.google.com/go/internal/rpcreplay/proto/rpcreplay/rpcreplay.pb.go
generated
vendored
@@ -1,170 +0,0 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: rpcreplay.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package rpcreplay is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
rpcreplay.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Entry
|
||||
*/
|
||||
package rpcreplay
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import google_protobuf "github.com/golang/protobuf/ptypes/any"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Entry_Kind int32
|
||||
|
||||
const (
|
||||
Entry_TYPE_UNSPECIFIED Entry_Kind = 0
|
||||
// A unary request.
|
||||
// method: the full name of the method
|
||||
// message: the request proto
|
||||
// is_error: false
|
||||
// ref_index: 0
|
||||
Entry_REQUEST Entry_Kind = 1
|
||||
// A unary response.
|
||||
// method: the full name of the method
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto
|
||||
// else: the response proto
|
||||
// ref_index: index in the sequence of Entries of matching request (1-based)
|
||||
Entry_RESPONSE Entry_Kind = 2
|
||||
// A method that creates a stream.
|
||||
// method: the full name of the method
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto
|
||||
// else: nil
|
||||
// ref_index: 0
|
||||
Entry_CREATE_STREAM Entry_Kind = 3
|
||||
// A call to Send on the client returned by a stream-creating method.
|
||||
// method: unset
|
||||
// message: the proto being sent
|
||||
// is_error: false
|
||||
// ref_index: index of matching CREATE_STREAM entry (1-based)
|
||||
Entry_SEND Entry_Kind = 4
|
||||
// A call to Recv on the client returned by a stream-creating method.
|
||||
// method: unset
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto, or nil on EOF
|
||||
// else: the received message
|
||||
// ref_index: index of matching CREATE_STREAM entry
|
||||
Entry_RECV Entry_Kind = 5
|
||||
)
|
||||
|
||||
var Entry_Kind_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "REQUEST",
|
||||
2: "RESPONSE",
|
||||
3: "CREATE_STREAM",
|
||||
4: "SEND",
|
||||
5: "RECV",
|
||||
}
|
||||
var Entry_Kind_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"REQUEST": 1,
|
||||
"RESPONSE": 2,
|
||||
"CREATE_STREAM": 3,
|
||||
"SEND": 4,
|
||||
"RECV": 5,
|
||||
}
|
||||
|
||||
func (x Entry_Kind) String() string {
|
||||
return proto.EnumName(Entry_Kind_name, int32(x))
|
||||
}
|
||||
func (Entry_Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
|
||||
|
||||
// An Entry represents a single RPC activity, typically a request or response.
|
||||
type Entry struct {
|
||||
Kind Entry_Kind `protobuf:"varint,1,opt,name=kind,enum=rpcreplay.Entry_Kind" json:"kind,omitempty"`
|
||||
Method string `protobuf:"bytes,2,opt,name=method" json:"method,omitempty"`
|
||||
Message *google_protobuf.Any `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"`
|
||||
IsError bool `protobuf:"varint,4,opt,name=is_error,json=isError" json:"is_error,omitempty"`
|
||||
RefIndex int32 `protobuf:"varint,5,opt,name=ref_index,json=refIndex" json:"ref_index,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Entry) Reset() { *m = Entry{} }
|
||||
func (m *Entry) String() string { return proto.CompactTextString(m) }
|
||||
func (*Entry) ProtoMessage() {}
|
||||
func (*Entry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *Entry) GetKind() Entry_Kind {
|
||||
if m != nil {
|
||||
return m.Kind
|
||||
}
|
||||
return Entry_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (m *Entry) GetMethod() string {
|
||||
if m != nil {
|
||||
return m.Method
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Entry) GetMessage() *google_protobuf.Any {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Entry) GetIsError() bool {
|
||||
if m != nil {
|
||||
return m.IsError
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Entry) GetRefIndex() int32 {
|
||||
if m != nil {
|
||||
return m.RefIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Entry)(nil), "rpcreplay.Entry")
|
||||
proto.RegisterEnum("rpcreplay.Entry_Kind", Entry_Kind_name, Entry_Kind_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("rpcreplay.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 289 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x44, 0x8e, 0xdf, 0x4e, 0xc2, 0x30,
|
||||
0x14, 0xc6, 0x2d, 0x6c, 0x30, 0x0e, 0xfe, 0xa9, 0x0d, 0x9a, 0xa1, 0x37, 0x0b, 0x57, 0xf3, 0xa6,
|
||||
0x24, 0xf8, 0x04, 0x04, 0x8e, 0x09, 0x31, 0x22, 0xb6, 0xc3, 0xc4, 0x1b, 0x17, 0x70, 0x05, 0x17,
|
||||
0xa1, 0x25, 0xdd, 0x4c, 0xdc, 0x6b, 0xf8, 0xc4, 0x66, 0x13, 0xf4, 0xae, 0xbf, 0x7e, 0xbf, 0x9c,
|
||||
0xef, 0x83, 0x33, 0xbb, 0x7b, 0xb3, 0x6a, 0xb7, 0x59, 0x14, 0x7c, 0x67, 0x4d, 0x6e, 0x58, 0xeb,
|
||||
0xef, 0xe3, 0xaa, 0xbb, 0x36, 0x66, 0xbd, 0x51, 0xfd, 0x2a, 0x58, 0x7e, 0xae, 0xfa, 0x0b, 0xbd,
|
||||
0xb7, 0x7a, 0xdf, 0x35, 0x70, 0x51, 0xe7, 0xb6, 0x60, 0x37, 0xe0, 0x7c, 0xa4, 0x3a, 0xf1, 0x49,
|
||||
0x40, 0xc2, 0xd3, 0xc1, 0x05, 0xff, 0xbf, 0x57, 0xe5, 0xfc, 0x3e, 0xd5, 0x89, 0xa8, 0x14, 0x76,
|
||||
0x09, 0x8d, 0xad, 0xca, 0xdf, 0x4d, 0xe2, 0xd7, 0x02, 0x12, 0xb6, 0xc4, 0x9e, 0x18, 0x87, 0xe6,
|
||||
0x56, 0x65, 0xd9, 0x62, 0xad, 0xfc, 0x7a, 0x40, 0xc2, 0xf6, 0xa0, 0xc3, 0x7f, 0x9b, 0xf9, 0xa1,
|
||||
0x99, 0x0f, 0x75, 0x21, 0x0e, 0x12, 0xeb, 0x82, 0x97, 0x66, 0xb1, 0xb2, 0xd6, 0x58, 0xdf, 0x09,
|
||||
0x48, 0xe8, 0x89, 0x66, 0x9a, 0x61, 0x89, 0xec, 0x1a, 0x5a, 0x56, 0xad, 0xe2, 0x54, 0x27, 0xea,
|
||||
0xcb, 0x77, 0x03, 0x12, 0xba, 0xc2, 0xb3, 0x6a, 0x35, 0x29, 0xb9, 0xf7, 0x0a, 0x4e, 0xb9, 0x86,
|
||||
0x75, 0x80, 0x46, 0x2f, 0x33, 0x8c, 0xe7, 0x53, 0x39, 0xc3, 0xd1, 0xe4, 0x6e, 0x82, 0x63, 0x7a,
|
||||
0xc4, 0xda, 0xd0, 0x14, 0xf8, 0x34, 0x47, 0x19, 0x51, 0xc2, 0x8e, 0xc1, 0x13, 0x28, 0x67, 0x8f,
|
||||
0x53, 0x89, 0xb4, 0xc6, 0xce, 0xe1, 0x64, 0x24, 0x70, 0x18, 0x61, 0x2c, 0x23, 0x81, 0xc3, 0x07,
|
||||
0x5a, 0x67, 0x1e, 0x38, 0x12, 0xa7, 0x63, 0xea, 0x94, 0x2f, 0x81, 0xa3, 0x67, 0xea, 0x2e, 0x1b,
|
||||
0xd5, 0xdc, 0xdb, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x9b, 0x9d, 0x4f, 0x54, 0x01, 0x00,
|
||||
0x00,
|
||||
}
|
||||
71
vendor/cloud.google.com/go/internal/rpcreplay/proto/rpcreplay/rpcreplay.proto
generated
vendored
71
vendor/cloud.google.com/go/internal/rpcreplay/proto/rpcreplay/rpcreplay.proto
generated
vendored
@@ -1,71 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package rpcreplay;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
// An Entry represents a single RPC activity, typically a request or response.
|
||||
message Entry {
|
||||
enum Kind {
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// A unary request.
|
||||
// method: the full name of the method
|
||||
// message: the request proto
|
||||
// is_error: false
|
||||
// ref_index: 0
|
||||
REQUEST = 1;
|
||||
|
||||
// A unary response.
|
||||
// method: the full name of the method
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto
|
||||
// else: the response proto
|
||||
// ref_index: index in the sequence of Entries of matching request (1-based)
|
||||
RESPONSE = 2;
|
||||
|
||||
// A method that creates a stream.
|
||||
// method: the full name of the method
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto
|
||||
// else: nil
|
||||
// ref_index: 0
|
||||
CREATE_STREAM = 3;
|
||||
|
||||
// A call to Send on the client returned by a stream-creating method.
|
||||
// method: unset
|
||||
// message: the proto being sent
|
||||
// is_error: false
|
||||
// ref_index: index of matching CREATE_STREAM entry (1-based)
|
||||
SEND = 4; // message sent on stream
|
||||
|
||||
// A call to Recv on the client returned by a stream-creating method.
|
||||
// method: unset
|
||||
// message:
|
||||
// if is_error: a google.rpc.Status proto, or nil on EOF
|
||||
// else: the received message
|
||||
// ref_index: index of matching CREATE_STREAM entry
|
||||
RECV = 5; // message received from stream
|
||||
}
|
||||
|
||||
Kind kind = 1;
|
||||
string method = 2; // method name
|
||||
google.protobuf.Any message = 3; // request, response or error status
|
||||
bool is_error = 4; // was response an error?
|
||||
int32 ref_index = 5; // for RESPONSE, index of matching request;
|
||||
// for SEND/RECV, index of CREATE_STREAM
|
||||
}
|
||||
689
vendor/cloud.google.com/go/internal/rpcreplay/rpcreplay.go
generated
vendored
689
vendor/cloud.google.com/go/internal/rpcreplay/rpcreplay.go
generated
vendored
@@ -1,689 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rpcreplay
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
pb "cloud.google.com/go/internal/rpcreplay/proto/rpcreplay"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/any"
|
||||
spb "google.golang.org/genproto/googleapis/rpc/status"
|
||||
)
|
||||
|
||||
// A Recorder records RPCs for later playback.
|
||||
type Recorder struct {
|
||||
mu sync.Mutex
|
||||
w *bufio.Writer
|
||||
f *os.File
|
||||
next int
|
||||
err error
|
||||
}
|
||||
|
||||
// NewRecorder creates a recorder that writes to filename. The file will
|
||||
// also store the initial bytes for retrieval during replay.
|
||||
//
|
||||
// You must call Close on the Recorder to ensure that all data is written.
|
||||
func NewRecorder(filename string, initial []byte) (*Recorder, error) {
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rec, err := NewRecorderWriter(f, initial)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
return nil, err
|
||||
}
|
||||
rec.f = f
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
// NewRecorderWriter creates a recorder that writes to w. The initial
|
||||
// bytes will also be written to w for retrieval during replay.
|
||||
//
|
||||
// You must call Close on the Recorder to ensure that all data is written.
|
||||
func NewRecorderWriter(w io.Writer, initial []byte) (*Recorder, error) {
|
||||
bw := bufio.NewWriter(w)
|
||||
if err := writeHeader(bw, initial); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Recorder{w: bw, next: 1}, nil
|
||||
}
|
||||
|
||||
// DialOptions returns the options that must be passed to grpc.Dial
|
||||
// to enable recording.
|
||||
func (r *Recorder) DialOptions() []grpc.DialOption {
|
||||
return []grpc.DialOption{
|
||||
grpc.WithUnaryInterceptor(r.interceptUnary),
|
||||
grpc.WithStreamInterceptor(r.interceptStream),
|
||||
}
|
||||
}
|
||||
|
||||
// Close saves any unwritten information.
|
||||
func (r *Recorder) Close() error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
err := r.w.Flush()
|
||||
if r.f != nil {
|
||||
if err2 := r.f.Close(); err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Intercepts all unary (non-stream) RPCs.
|
||||
func (r *Recorder) interceptUnary(ctx context.Context, method string, req, res interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
ereq := &entry{
|
||||
kind: pb.Entry_REQUEST,
|
||||
method: method,
|
||||
msg: message{msg: req.(proto.Message)},
|
||||
}
|
||||
|
||||
refIndex, err := r.writeEntry(ereq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ierr := invoker(ctx, method, req, res, cc, opts...)
|
||||
eres := &entry{
|
||||
kind: pb.Entry_RESPONSE,
|
||||
refIndex: refIndex,
|
||||
}
|
||||
// If the error is not a gRPC status, then something more
|
||||
// serious is wrong. More significantly, we have no way
|
||||
// of serializing an arbitrary error. So just return it
|
||||
// without recording the response.
|
||||
if _, ok := status.FromError(ierr); !ok {
|
||||
r.mu.Lock()
|
||||
r.err = fmt.Errorf("saw non-status error in %s response: %v (%T)", method, ierr, ierr)
|
||||
r.mu.Unlock()
|
||||
return ierr
|
||||
}
|
||||
eres.msg.set(res, ierr)
|
||||
if _, err := r.writeEntry(eres); err != nil {
|
||||
return err
|
||||
}
|
||||
return ierr
|
||||
}
|
||||
|
||||
func (r *Recorder) writeEntry(e *entry) (int, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
}
|
||||
err := writeEntry(r.w, e)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return 0, err
|
||||
}
|
||||
n := r.next
|
||||
r.next++
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *Recorder) interceptStream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
cstream, serr := streamer(ctx, desc, cc, method, opts...)
|
||||
e := &entry{
|
||||
kind: pb.Entry_CREATE_STREAM,
|
||||
method: method,
|
||||
}
|
||||
e.msg.set(nil, serr)
|
||||
refIndex, err := r.writeEntry(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &recClientStream{
|
||||
ctx: ctx,
|
||||
rec: r,
|
||||
cstream: cstream,
|
||||
refIndex: refIndex,
|
||||
}, serr
|
||||
}
|
||||
|
||||
// A recClientStream implements the gprc.ClientStream interface.
|
||||
// It behaves exactly like the default ClientStream, but also
|
||||
// records all messages sent and received.
|
||||
type recClientStream struct {
|
||||
ctx context.Context
|
||||
rec *Recorder
|
||||
cstream grpc.ClientStream
|
||||
refIndex int
|
||||
}
|
||||
|
||||
func (rcs *recClientStream) Context() context.Context { return rcs.ctx }
|
||||
|
||||
func (rcs *recClientStream) SendMsg(m interface{}) error {
|
||||
serr := rcs.cstream.SendMsg(m)
|
||||
e := &entry{
|
||||
kind: pb.Entry_SEND,
|
||||
refIndex: rcs.refIndex,
|
||||
}
|
||||
e.msg.set(m, serr)
|
||||
if _, err := rcs.rec.writeEntry(e); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
||||
func (rcs *recClientStream) RecvMsg(m interface{}) error {
|
||||
serr := rcs.cstream.RecvMsg(m)
|
||||
e := &entry{
|
||||
kind: pb.Entry_RECV,
|
||||
refIndex: rcs.refIndex,
|
||||
}
|
||||
e.msg.set(m, serr)
|
||||
if _, err := rcs.rec.writeEntry(e); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
||||
func (rcs *recClientStream) Header() (metadata.MD, error) {
|
||||
// TODO(jba): record.
|
||||
return rcs.cstream.Header()
|
||||
}
|
||||
|
||||
func (rcs *recClientStream) Trailer() metadata.MD {
|
||||
// TODO(jba): record.
|
||||
return rcs.cstream.Trailer()
|
||||
}
|
||||
|
||||
func (rcs *recClientStream) CloseSend() error {
|
||||
// TODO(jba): record.
|
||||
return rcs.cstream.CloseSend()
|
||||
}
|
||||
|
||||
// A Replayer replays a set of RPCs saved by a Recorder.
|
||||
type Replayer struct {
|
||||
initial []byte // initial state
|
||||
log func(format string, v ...interface{}) // for debugging
|
||||
|
||||
mu sync.Mutex
|
||||
calls []*call
|
||||
streams []*stream
|
||||
}
|
||||
|
||||
// A call represents a unary RPC, with a request and response (or error).
|
||||
type call struct {
|
||||
method string
|
||||
request proto.Message
|
||||
response message
|
||||
}
|
||||
|
||||
// A stream represents a gRPC stream, with an initial create-stream call, followed by
|
||||
// zero or more sends and/or receives.
|
||||
type stream struct {
|
||||
method string
|
||||
createIndex int
|
||||
createErr error // error from create call
|
||||
sends []message
|
||||
recvs []message
|
||||
}
|
||||
|
||||
// NewReplayer creates a Replayer that reads from filename.
|
||||
func NewReplayer(filename string) (*Replayer, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return NewReplayerReader(f)
|
||||
}
|
||||
|
||||
// NewReplayerReader creates a Replayer that reads from r.
|
||||
func NewReplayerReader(r io.Reader) (*Replayer, error) {
|
||||
rep := &Replayer{
|
||||
log: func(string, ...interface{}) {},
|
||||
}
|
||||
if err := rep.read(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rep, nil
|
||||
}
|
||||
|
||||
// read reads the stream of recorded entries.
|
||||
// It matches requests with responses, with each pair grouped
|
||||
// into a call struct.
|
||||
func (rep *Replayer) read(r io.Reader) error {
|
||||
r = bufio.NewReader(r)
|
||||
bytes, err := readHeader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rep.initial = bytes
|
||||
|
||||
callsByIndex := map[int]*call{}
|
||||
streamsByIndex := map[int]*stream{}
|
||||
for i := 1; ; i++ {
|
||||
e, err := readEntry(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
switch e.kind {
|
||||
case pb.Entry_REQUEST:
|
||||
callsByIndex[i] = &call{
|
||||
method: e.method,
|
||||
request: e.msg.msg,
|
||||
}
|
||||
|
||||
case pb.Entry_RESPONSE:
|
||||
call := callsByIndex[e.refIndex]
|
||||
if call == nil {
|
||||
return fmt.Errorf("replayer: no request for response #%d", i)
|
||||
}
|
||||
delete(callsByIndex, e.refIndex)
|
||||
call.response = e.msg
|
||||
rep.calls = append(rep.calls, call)
|
||||
|
||||
case pb.Entry_CREATE_STREAM:
|
||||
s := &stream{method: e.method, createIndex: i}
|
||||
s.createErr = e.msg.err
|
||||
streamsByIndex[i] = s
|
||||
rep.streams = append(rep.streams, s)
|
||||
|
||||
case pb.Entry_SEND:
|
||||
s := streamsByIndex[e.refIndex]
|
||||
if s == nil {
|
||||
return fmt.Errorf("replayer: no stream for send #%d", i)
|
||||
}
|
||||
s.sends = append(s.sends, e.msg)
|
||||
|
||||
case pb.Entry_RECV:
|
||||
s := streamsByIndex[e.refIndex]
|
||||
if s == nil {
|
||||
return fmt.Errorf("replayer: no stream for recv #%d", i)
|
||||
}
|
||||
s.recvs = append(s.recvs, e.msg)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("replayer: unknown kind %s", e.kind)
|
||||
}
|
||||
}
|
||||
if len(callsByIndex) > 0 {
|
||||
return fmt.Errorf("replayer: %d unmatched requests", len(callsByIndex))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DialOptions returns the options that must be passed to grpc.Dial
|
||||
// to enable replaying.
|
||||
func (r *Replayer) DialOptions() []grpc.DialOption {
|
||||
return []grpc.DialOption{
|
||||
// On replay, we make no RPCs, which means the connection may be closed
|
||||
// before the normally async Dial completes. Making the Dial synchronous
|
||||
// fixes that.
|
||||
grpc.WithBlock(),
|
||||
grpc.WithUnaryInterceptor(r.interceptUnary),
|
||||
grpc.WithStreamInterceptor(r.interceptStream),
|
||||
}
|
||||
}
|
||||
|
||||
// Initial returns the initial state saved by the Recorder.
|
||||
func (r *Replayer) Initial() []byte { return r.initial }
|
||||
|
||||
// SetLogFunc sets a function to be used for debug logging. The function
|
||||
// should be safe to be called from multiple goroutines.
|
||||
func (r *Replayer) SetLogFunc(f func(format string, v ...interface{})) {
|
||||
r.log = f
|
||||
}
|
||||
|
||||
// Close closes the Replayer.
|
||||
func (r *Replayer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Replayer) interceptUnary(_ context.Context, method string, req, res interface{}, _ *grpc.ClientConn, _ grpc.UnaryInvoker, _ ...grpc.CallOption) error {
|
||||
mreq := req.(proto.Message)
|
||||
r.log("request %s (%s)", method, req)
|
||||
call := r.extractCall(method, mreq)
|
||||
if call == nil {
|
||||
return fmt.Errorf("replayer: request not found: %s", mreq)
|
||||
}
|
||||
r.log("returning %v", call.response)
|
||||
if call.response.err != nil {
|
||||
return call.response.err
|
||||
}
|
||||
proto.Merge(res.(proto.Message), call.response.msg) // copy msg into res
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Replayer) interceptStream(ctx context.Context, _ *grpc.StreamDesc, _ *grpc.ClientConn, method string, _ grpc.Streamer, _ ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
r.log("create-stream %s", method)
|
||||
str := r.extractStream(method)
|
||||
if str == nil {
|
||||
return nil, fmt.Errorf("replayer: stream not found for method %s", method)
|
||||
}
|
||||
if str.createErr != nil {
|
||||
return nil, str.createErr
|
||||
}
|
||||
return &repClientStream{ctx: ctx, str: str}, nil
|
||||
}
|
||||
|
||||
type repClientStream struct {
|
||||
ctx context.Context
|
||||
str *stream
|
||||
}
|
||||
|
||||
func (rcs *repClientStream) Context() context.Context { return rcs.ctx }
|
||||
|
||||
func (rcs *repClientStream) SendMsg(m interface{}) error {
|
||||
if len(rcs.str.sends) == 0 {
|
||||
return fmt.Errorf("replayer: no more sends for stream %s, created at index %d",
|
||||
rcs.str.method, rcs.str.createIndex)
|
||||
}
|
||||
// TODO(jba): Do not assume that the sends happen in the same order on replay.
|
||||
msg := rcs.str.sends[0]
|
||||
rcs.str.sends = rcs.str.sends[1:]
|
||||
return msg.err
|
||||
}
|
||||
|
||||
func (rcs *repClientStream) RecvMsg(m interface{}) error {
|
||||
if len(rcs.str.recvs) == 0 {
|
||||
return fmt.Errorf("replayer: no more receives for stream %s, created at index %d",
|
||||
rcs.str.method, rcs.str.createIndex)
|
||||
}
|
||||
msg := rcs.str.recvs[0]
|
||||
rcs.str.recvs = rcs.str.recvs[1:]
|
||||
if msg.err != nil {
|
||||
return msg.err
|
||||
}
|
||||
proto.Merge(m.(proto.Message), msg.msg) // copy msg into m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcs *repClientStream) Header() (metadata.MD, error) {
|
||||
log.Printf("replay: stream metadata not supported")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (rcs *repClientStream) Trailer() metadata.MD {
|
||||
log.Printf("replay: stream metadata not supported")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcs *repClientStream) CloseSend() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractCall finds the first call in the list with the same method
|
||||
// and request. It returns nil if it can't find such a call.
|
||||
func (r *Replayer) extractCall(method string, req proto.Message) *call {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
for i, call := range r.calls {
|
||||
if call == nil {
|
||||
continue
|
||||
}
|
||||
if method == call.method && proto.Equal(req, call.request) {
|
||||
r.calls[i] = nil // nil out this call so we don't reuse it
|
||||
return call
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Replayer) extractStream(method string) *stream {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
for i, stream := range r.streams {
|
||||
if stream == nil {
|
||||
continue
|
||||
}
|
||||
if method == stream.method {
|
||||
r.streams[i] = nil
|
||||
return stream
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fprint reads the entries from filename and writes them to w in human-readable form.
|
||||
// It is intended for debugging.
|
||||
func Fprint(w io.Writer, filename string) error {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return FprintReader(w, f)
|
||||
}
|
||||
|
||||
// FprintReader reads the entries from r and writes them to w in human-readable form.
|
||||
// It is intended for debugging.
|
||||
func FprintReader(w io.Writer, r io.Reader) error {
|
||||
initial, err := readHeader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w, "initial state: %q\n", string(initial))
|
||||
for i := 1; ; i++ {
|
||||
e, err := readEntry(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s := "message"
|
||||
if e.msg.err != nil {
|
||||
s = "error"
|
||||
}
|
||||
fmt.Fprintf(w, "#%d: kind: %s, method: %s, ref index: %d, %s:\n",
|
||||
i, e.kind, e.method, e.refIndex, s)
|
||||
if e.msg.err == nil {
|
||||
if err := proto.MarshalText(w, e.msg.msg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "%v\n", e.msg.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An entry holds one gRPC action (request, response, etc.).
|
||||
type entry struct {
|
||||
kind pb.Entry_Kind
|
||||
method string
|
||||
msg message
|
||||
refIndex int // index of corresponding request or create-stream
|
||||
}
|
||||
|
||||
func (e1 *entry) equal(e2 *entry) bool {
|
||||
if e1 == nil && e2 == nil {
|
||||
return true
|
||||
}
|
||||
if e1 == nil || e2 == nil {
|
||||
return false
|
||||
}
|
||||
return e1.kind == e2.kind &&
|
||||
e1.method == e2.method &&
|
||||
proto.Equal(e1.msg.msg, e2.msg.msg) &&
|
||||
errEqual(e1.msg.err, e2.msg.err) &&
|
||||
e1.refIndex == e2.refIndex
|
||||
}
|
||||
|
||||
func errEqual(e1, e2 error) bool {
|
||||
if e1 == e2 {
|
||||
return true
|
||||
}
|
||||
s1, ok1 := status.FromError(e1)
|
||||
s2, ok2 := status.FromError(e2)
|
||||
if !ok1 || !ok2 {
|
||||
return false
|
||||
}
|
||||
return proto.Equal(s1.Proto(), s2.Proto())
|
||||
}
|
||||
|
||||
// message holds either a single proto.Message or an error.
|
||||
type message struct {
|
||||
msg proto.Message
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *message) set(msg interface{}, err error) {
|
||||
m.err = err
|
||||
if err != io.EOF && msg != nil {
|
||||
m.msg = msg.(proto.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// File format:
|
||||
// header
|
||||
// sequence of Entry protos
|
||||
//
|
||||
// Header format:
|
||||
// magic string
|
||||
// a record containing the bytes of the initial state
|
||||
|
||||
const magic = "RPCReplay"
|
||||
|
||||
func writeHeader(w io.Writer, initial []byte) error {
|
||||
if _, err := io.WriteString(w, magic); err != nil {
|
||||
return err
|
||||
}
|
||||
return writeRecord(w, initial)
|
||||
}
|
||||
|
||||
func readHeader(r io.Reader) ([]byte, error) {
|
||||
var buf [len(magic)]byte
|
||||
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
||||
if err == io.EOF {
|
||||
err = errors.New("rpcreplay: empty replay file")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if string(buf[:]) != magic {
|
||||
return nil, errors.New("rpcreplay: not a replay file (does not begin with magic string)")
|
||||
}
|
||||
bytes, err := readRecord(r)
|
||||
if err == io.EOF {
|
||||
err = errors.New("rpcreplay: missing initial state")
|
||||
}
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
func writeEntry(w io.Writer, e *entry) error {
|
||||
var m proto.Message
|
||||
if e.msg.err != nil && e.msg.err != io.EOF {
|
||||
s, ok := status.FromError(e.msg.err)
|
||||
if !ok {
|
||||
return fmt.Errorf("rpcreplay: error %v is not a Status", e.msg.err)
|
||||
}
|
||||
m = s.Proto()
|
||||
} else {
|
||||
m = e.msg.msg
|
||||
}
|
||||
var a *any.Any
|
||||
var err error
|
||||
if m != nil {
|
||||
a, err = ptypes.MarshalAny(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
pe := &pb.Entry{
|
||||
Kind: e.kind,
|
||||
Method: e.method,
|
||||
Message: a,
|
||||
IsError: e.msg.err != nil,
|
||||
RefIndex: int32(e.refIndex),
|
||||
}
|
||||
bytes, err := proto.Marshal(pe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeRecord(w, bytes)
|
||||
}
|
||||
|
||||
func readEntry(r io.Reader) (*entry, error) {
|
||||
buf, err := readRecord(r)
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pe pb.Entry
|
||||
if err := proto.Unmarshal(buf, &pe); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var msg message
|
||||
if pe.Message != nil {
|
||||
var any ptypes.DynamicAny
|
||||
if err := ptypes.UnmarshalAny(pe.Message, &any); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pe.IsError {
|
||||
msg.err = status.ErrorProto(any.Message.(*spb.Status))
|
||||
} else {
|
||||
msg.msg = any.Message
|
||||
}
|
||||
} else if pe.IsError {
|
||||
msg.err = io.EOF
|
||||
} else if pe.Kind != pb.Entry_CREATE_STREAM {
|
||||
return nil, errors.New("rpcreplay: entry with nil message and false is_error")
|
||||
}
|
||||
return &entry{
|
||||
kind: pe.Kind,
|
||||
method: pe.Method,
|
||||
msg: msg,
|
||||
refIndex: int(pe.RefIndex),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// A record consists of an unsigned 32-bit little-endian length L followed by L
|
||||
// bytes.
|
||||
|
||||
func writeRecord(w io.Writer, data []byte) error {
|
||||
if err := binary.Write(w, binary.LittleEndian, uint32(len(data))); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
func readRecord(r io.Reader) ([]byte, error) {
|
||||
var size uint32
|
||||
if err := binary.Read(r, binary.LittleEndian, &size); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
362
vendor/cloud.google.com/go/internal/rpcreplay/rpcreplay_test.go
generated
vendored
362
vendor/cloud.google.com/go/internal/rpcreplay/rpcreplay_test.go
generated
vendored
@@ -1,362 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rpcreplay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
ipb "cloud.google.com/go/internal/rpcreplay/proto/intstore"
|
||||
rpb "cloud.google.com/go/internal/rpcreplay/proto/rpcreplay"
|
||||
"cloud.google.com/go/internal/testutil"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestRecordIO(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
want := []byte{1, 2, 3}
|
||||
if err := writeRecord(buf, want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := readRecord(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderIO(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
want := []byte{1, 2, 3}
|
||||
if err := writeHeader(buf, want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := readHeader(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !testutil.Equal(got, want) {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
// readHeader errors
|
||||
for _, contents := range []string{"", "badmagic", "gRPCReplay"} {
|
||||
if _, err := readHeader(bytes.NewBufferString(contents)); err == nil {
|
||||
t.Errorf("%q: got nil, want error", contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryIO(t *testing.T) {
|
||||
for i, want := range []*entry{
|
||||
{
|
||||
kind: rpb.Entry_REQUEST,
|
||||
method: "method",
|
||||
msg: message{msg: &rpb.Entry{}},
|
||||
refIndex: 7,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RESPONSE,
|
||||
method: "method",
|
||||
msg: message{err: status.Error(codes.NotFound, "not found")},
|
||||
refIndex: 8,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
method: "method",
|
||||
msg: message{err: io.EOF},
|
||||
refIndex: 3,
|
||||
},
|
||||
} {
|
||||
buf := &bytes.Buffer{}
|
||||
if err := writeEntry(buf, want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := readEntry(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !got.equal(want) {
|
||||
t.Errorf("#%d: got %v, want %v", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var initialState = []byte{1, 2, 3}
|
||||
|
||||
func TestRecord(t *testing.T) {
|
||||
srv := newIntStoreServer()
|
||||
defer srv.stop()
|
||||
buf := record(t, srv)
|
||||
|
||||
gotIstate, err := readHeader(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !testutil.Equal(gotIstate, initialState) {
|
||||
t.Fatalf("got %v, want %v", gotIstate, initialState)
|
||||
}
|
||||
item := &ipb.Item{Name: "a", Value: 1}
|
||||
wantEntries := []*entry{
|
||||
// Set
|
||||
{
|
||||
kind: rpb.Entry_REQUEST,
|
||||
method: "/intstore.IntStore/Set",
|
||||
msg: message{msg: item},
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RESPONSE,
|
||||
msg: message{msg: &ipb.SetResponse{PrevValue: 0}},
|
||||
refIndex: 1,
|
||||
},
|
||||
// Get
|
||||
{
|
||||
kind: rpb.Entry_REQUEST,
|
||||
method: "/intstore.IntStore/Get",
|
||||
msg: message{msg: &ipb.GetRequest{Name: "a"}},
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RESPONSE,
|
||||
msg: message{msg: item},
|
||||
refIndex: 3,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_REQUEST,
|
||||
method: "/intstore.IntStore/Get",
|
||||
msg: message{msg: &ipb.GetRequest{Name: "x"}},
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RESPONSE,
|
||||
msg: message{err: status.Error(codes.NotFound, `"x"`)},
|
||||
refIndex: 5,
|
||||
},
|
||||
// ListItems
|
||||
{ // entry #7
|
||||
kind: rpb.Entry_CREATE_STREAM,
|
||||
method: "/intstore.IntStore/ListItems",
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_SEND,
|
||||
msg: message{msg: &ipb.ListItemsRequest{}},
|
||||
refIndex: 7,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{msg: item},
|
||||
refIndex: 7,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{err: io.EOF},
|
||||
refIndex: 7,
|
||||
},
|
||||
// SetStream
|
||||
{ // entry #11
|
||||
kind: rpb.Entry_CREATE_STREAM,
|
||||
method: "/intstore.IntStore/SetStream",
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_SEND,
|
||||
msg: message{msg: &ipb.Item{Name: "b", Value: 2}},
|
||||
refIndex: 11,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_SEND,
|
||||
msg: message{msg: &ipb.Item{Name: "c", Value: 3}},
|
||||
refIndex: 11,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{msg: &ipb.Summary{Count: 2}},
|
||||
refIndex: 11,
|
||||
},
|
||||
|
||||
// StreamChat
|
||||
{ // entry #15
|
||||
kind: rpb.Entry_CREATE_STREAM,
|
||||
method: "/intstore.IntStore/StreamChat",
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_SEND,
|
||||
msg: message{msg: &ipb.Item{Name: "d", Value: 4}},
|
||||
refIndex: 15,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{msg: &ipb.Item{Name: "d", Value: 4}},
|
||||
refIndex: 15,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_SEND,
|
||||
msg: message{msg: &ipb.Item{Name: "e", Value: 5}},
|
||||
refIndex: 15,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{msg: &ipb.Item{Name: "e", Value: 5}},
|
||||
refIndex: 15,
|
||||
},
|
||||
{
|
||||
kind: rpb.Entry_RECV,
|
||||
msg: message{err: io.EOF},
|
||||
refIndex: 15,
|
||||
},
|
||||
}
|
||||
for i, w := range wantEntries {
|
||||
g, err := readEntry(buf)
|
||||
if err != nil {
|
||||
t.Fatalf("%#d: %v", i+1, err)
|
||||
}
|
||||
if !g.equal(w) {
|
||||
t.Errorf("#%d:\ngot %+v\nwant %+v", i+1, g, w)
|
||||
}
|
||||
}
|
||||
g, err := readEntry(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if g != nil {
|
||||
t.Errorf("\ngot %+v\nwant nil", g)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplay(t *testing.T) {
|
||||
srv := newIntStoreServer()
|
||||
defer srv.stop()
|
||||
|
||||
buf := record(t, srv)
|
||||
rep, err := NewReplayerReader(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := rep.Initial(), initialState; !testutil.Equal(got, want) {
|
||||
t.Fatalf("got %v, want %v", got, want)
|
||||
}
|
||||
// Replay the test.
|
||||
testService(t, srv.Addr, rep.DialOptions())
|
||||
}
|
||||
|
||||
func record(t *testing.T, srv *intStoreServer) *bytes.Buffer {
|
||||
buf := &bytes.Buffer{}
|
||||
rec, err := NewRecorderWriter(buf, initialState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testService(t, srv.Addr, rec.DialOptions())
|
||||
if err := rec.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func testService(t *testing.T, addr string, opts []grpc.DialOption) {
|
||||
conn, err := grpc.Dial(addr,
|
||||
append([]grpc.DialOption{grpc.WithInsecure()}, opts...)...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := ipb.NewIntStoreClient(conn)
|
||||
ctx := context.Background()
|
||||
item := &ipb.Item{Name: "a", Value: 1}
|
||||
res, err := client.Set(ctx, item)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.PrevValue != 0 {
|
||||
t.Errorf("got %d, want 0", res.PrevValue)
|
||||
}
|
||||
got, err := client.Get(ctx, &ipb.GetRequest{Name: "a"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !proto.Equal(got, item) {
|
||||
t.Errorf("got %v, want %v", got, item)
|
||||
}
|
||||
_, err = client.Get(ctx, &ipb.GetRequest{Name: "x"})
|
||||
if err == nil {
|
||||
t.Fatal("got nil, want error")
|
||||
}
|
||||
if _, ok := status.FromError(err); !ok {
|
||||
t.Errorf("got error type %T, want a grpc/status.Status", err)
|
||||
}
|
||||
|
||||
wantItems := []*ipb.Item{item}
|
||||
lic, err := client.ListItems(ctx, &ipb.ListItemsRequest{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; ; i++ {
|
||||
item, err := lic.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if i >= len(wantItems) || !proto.Equal(item, wantItems[i]) {
|
||||
t.Fatalf("%d: bad item", i)
|
||||
}
|
||||
}
|
||||
|
||||
ssc, err := client.SetStream(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
must := func(err error) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, name := range []string{"b", "c"} {
|
||||
must(ssc.Send(&ipb.Item{Name: name, Value: int32(i + 2)}))
|
||||
}
|
||||
summary, err := ssc.CloseAndRecv()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := summary.Count, int32(2); got != want {
|
||||
t.Fatalf("got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
chatc, err := client.StreamChat(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, name := range []string{"d", "e"} {
|
||||
item := &ipb.Item{Name: name, Value: int32(i + 4)}
|
||||
must(chatc.Send(item))
|
||||
got, err := chatc.Recv()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !proto.Equal(got, item) {
|
||||
t.Errorf("got %v, want %v", got, item)
|
||||
}
|
||||
}
|
||||
must(chatc.CloseSend())
|
||||
if _, err := chatc.Recv(); err != io.EOF {
|
||||
t.Fatalf("got %v, want EOF", err)
|
||||
}
|
||||
}
|
||||
29
vendor/cloud.google.com/go/internal/snipdoc/README.md
generated
vendored
Normal file
29
vendor/cloud.google.com/go/internal/snipdoc/README.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Snipdoc
|
||||
|
||||
Snipdoc is a simple tool for maintaining package documentation that contains
|
||||
code samples.
|
||||
|
||||
1. Create a subdirectory of your package to hold the following files. "internal"
|
||||
is a good name.
|
||||
|
||||
2. Write a template file (for example, "doc.template") with the text of your package documentation. The file
|
||||
should look exactly like you want your doc.go file to look, except for code
|
||||
snippets.
|
||||
Instead of embedding a code snippet, write a line consisting solely of
|
||||
|
||||
[NAME]
|
||||
|
||||
for your choice of NAME.
|
||||
|
||||
3. Write a snippets file (for example, "doc-snippets.go") as a valid Go source
|
||||
file. Begin each snippet you'd like to appear in your package docs with
|
||||
`//[ NAME` and end it with `//]`.
|
||||
|
||||
4. Construct your doc.go file with the command
|
||||
```
|
||||
awk -f snipdoc.awk doc-snippets.go doc.template
|
||||
```
|
||||
The file "sample-makefile" in this directory verifies that the
|
||||
snippets file compiles and safely constructs a doc.go file.
|
||||
|
||||
|
||||
16
vendor/cloud.google.com/go/internal/snipdoc/sample-makefile
generated
vendored
Normal file
16
vendor/cloud.google.com/go/internal/snipdoc/sample-makefile
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Build doc.go from template and snippets.
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
../doc.go: build doc-snippets.go doc.template snipdoc.awk
|
||||
@tmp=$$(mktemp) && \
|
||||
awk -f snipdoc.awk doc-snippets.go doc.template > $$tmp && \
|
||||
chmod +w $@ && \
|
||||
mv $$tmp $@ && \
|
||||
chmod -w $@
|
||||
@echo "wrote $@"
|
||||
|
||||
.PHONY: build
|
||||
|
||||
build:
|
||||
go build doc-snippets.go
|
||||
116
vendor/cloud.google.com/go/internal/snipdoc/snipdoc.awk
generated
vendored
Normal file
116
vendor/cloud.google.com/go/internal/snipdoc/snipdoc.awk
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
# Copyright 2017 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# snipdoc merges code snippets from Go source files into a template to
|
||||
# produce another go file (typically doc.go).
|
||||
#
|
||||
# Call with one or more .go files and a template file.
|
||||
#
|
||||
# awk -f snipmd.awk foo.go bar.go doc.template
|
||||
#
|
||||
# In the Go files, start a snippet with
|
||||
# //[ NAME
|
||||
# and end it with
|
||||
# //]
|
||||
#
|
||||
# In the template, write
|
||||
# [NAME]
|
||||
# on a line by itself to insert the snippet NAME on that line.
|
||||
#
|
||||
# The following transformations are made to the Go code:
|
||||
# - Trailing blank lines are removed.
|
||||
# - `ELLIPSIS` and `_ = ELLIPSIS` are replaced by `...`
|
||||
|
||||
|
||||
/^[ \t]*\/\/\[/ { # start snippet in Go file
|
||||
if (inGo()) {
|
||||
if ($2 == "") {
|
||||
die("missing snippet name")
|
||||
}
|
||||
curSnip = $2
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
/^[ \t]*\/\/]/ { # end snippet in Go file
|
||||
if (inGo()) {
|
||||
if (curSnip != "") {
|
||||
# Remove all trailing newlines.
|
||||
gsub(/[\t\n]+$/, "", snips[curSnip])
|
||||
curSnip = ""
|
||||
next
|
||||
} else {
|
||||
die("//] without corresponding //[")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENDFILE {
|
||||
if (curSnip != "") {
|
||||
die("unclosed snippet: " curSnip)
|
||||
}
|
||||
}
|
||||
|
||||
/^\[.*\]$/ { # Snippet marker in template file.
|
||||
if (inTemplate()) {
|
||||
name = substr($1, 2, length($1)-2)
|
||||
if (snips[name] == "") {
|
||||
die("no snippet named " name)
|
||||
}
|
||||
printf("%s\n", snips[name])
|
||||
afterSnip = 1
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
# Matches every line.
|
||||
{
|
||||
if (curSnip != "") {
|
||||
# If the first line in the snip has no indent, add the indent.
|
||||
if (snips[curSnip] == "") {
|
||||
if (index($0, "\t") == 1) {
|
||||
extraIndent = ""
|
||||
} else {
|
||||
extraIndent = "\t"
|
||||
}
|
||||
}
|
||||
|
||||
line = $0
|
||||
# Replace ELLIPSIS.
|
||||
gsub(/_ = ELLIPSIS/, "...", line)
|
||||
gsub(/ELLIPSIS/, "...", line)
|
||||
|
||||
snips[curSnip] = snips[curSnip] extraIndent line "\n"
|
||||
} else if (inTemplate()) {
|
||||
afterSnip = 0
|
||||
# Copy to output.
|
||||
print
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function inTemplate() {
|
||||
return match(FILENAME, /\.template$/)
|
||||
}
|
||||
|
||||
function inGo() {
|
||||
return match(FILENAME, /\.go$/)
|
||||
}
|
||||
|
||||
|
||||
function die(msg) {
|
||||
printf("%s:%d: %s\n", FILENAME, FNR, msg) > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
46
vendor/cloud.google.com/go/internal/testutil/cmp.go
generated
vendored
46
vendor/cloud.google.com/go/internal/testutil/cmp.go
generated
vendored
@@ -15,11 +15,7 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -55,45 +51,3 @@ func Diff(x, y interface{}, opts ...cmp.Option) string {
|
||||
opts = append(opts[:len(opts):len(opts)], defaultCmpOptions...)
|
||||
return cmp.Diff(x, y, opts...)
|
||||
}
|
||||
|
||||
// TODO(jba): remove the code below when cmpopts becomes available.
|
||||
|
||||
// IgnoreUnexported returns an Option that only ignores the immediate unexported
|
||||
// fields of a struct, including anonymous fields of unexported types.
|
||||
// In particular, unexported fields within the struct's exported fields
|
||||
// of struct types, including anonymous fields, will not be ignored unless the
|
||||
// type of the field itself is also passed to IgnoreUnexported.
|
||||
func IgnoreUnexported(typs ...interface{}) cmp.Option {
|
||||
ux := newUnexportedFilter(typs...)
|
||||
return cmp.FilterPath(ux.filter, cmp.Ignore())
|
||||
}
|
||||
|
||||
type unexportedFilter struct{ m map[reflect.Type]bool }
|
||||
|
||||
func newUnexportedFilter(typs ...interface{}) unexportedFilter {
|
||||
ux := unexportedFilter{m: make(map[reflect.Type]bool)}
|
||||
for _, typ := range typs {
|
||||
t := reflect.TypeOf(typ)
|
||||
if t == nil || t.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("invalid struct type: %T", typ))
|
||||
}
|
||||
ux.m[t] = true
|
||||
}
|
||||
return ux
|
||||
}
|
||||
func (xf unexportedFilter) filter(p cmp.Path) bool {
|
||||
if len(p) < 2 {
|
||||
return false
|
||||
}
|
||||
sf, ok := p[len(p)-1].(cmp.StructField)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return xf.m[p[len(p)-2].Type()] && !isExported(sf.Name())
|
||||
}
|
||||
|
||||
// isExported reports whether the identifier is exported.
|
||||
func isExported(id string) bool {
|
||||
r, _ := utf8.DecodeRuneInString(id)
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
|
||||
36
vendor/cloud.google.com/go/internal/testutil/context.go
generated
vendored
36
vendor/cloud.google.com/go/internal/testutil/context.go
generated
vendored
@@ -16,6 +16,7 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -59,13 +61,35 @@ func TokenSourceEnv(ctx context.Context, envVar string, scopes ...string) oauth2
|
||||
}
|
||||
return ts
|
||||
}
|
||||
jsonKey, err := ioutil.ReadFile(key)
|
||||
conf, err := jwtConfigFromFile(key, scopes)
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot read the JSON key file, err: %v", err)
|
||||
}
|
||||
conf, err := google.JWTConfigFromJSON(jsonKey, scopes...)
|
||||
if err != nil {
|
||||
log.Fatalf("google.JWTConfigFromJSON: %v", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
return conf.TokenSource(ctx)
|
||||
}
|
||||
|
||||
// JWTConfig reads the JSON private key file whose name is in the default
|
||||
// environment variable, and returns the jwt.Config it contains. It ignores
|
||||
// scopes.
|
||||
// If the environment variable is empty, it returns (nil, nil).
|
||||
func JWTConfig() (*jwt.Config, error) {
|
||||
return jwtConfigFromFile(os.Getenv(envPrivateKey), nil)
|
||||
}
|
||||
|
||||
// jwtConfigFromFile reads the given JSON private key file, and returns the
|
||||
// jwt.Config it contains.
|
||||
// If the filename is empty, it returns (nil, nil).
|
||||
func jwtConfigFromFile(filename string, scopes []string) (*jwt.Config, error) {
|
||||
if filename == "" {
|
||||
return nil, nil
|
||||
}
|
||||
jsonKey, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot read the JSON key file, err: %v", err)
|
||||
}
|
||||
conf, err := google.JWTConfigFromJSON(jsonKey, scopes...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("google.JWTConfigFromJSON: %v", err)
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
31
vendor/cloud.google.com/go/internal/testutil/server.go
generated
vendored
31
vendor/cloud.google.com/go/internal/testutil/server.go
generated
vendored
@@ -18,8 +18,10 @@ package testutil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// A Server is an in-process gRPC server, listening on a system-chosen port on
|
||||
@@ -71,3 +73,32 @@ func (s *Server) Close() {
|
||||
s.Gsrv.Stop()
|
||||
s.l.Close()
|
||||
}
|
||||
|
||||
// PageBounds converts an incoming page size and token from an RPC request into
|
||||
// slice bounds and the outgoing next-page token.
|
||||
//
|
||||
// PageBounds assumes that the complete, unpaginated list of items exists as a
|
||||
// single slice. In addition to the page size and token, PageBounds needs the
|
||||
// length of that slice.
|
||||
//
|
||||
// PageBounds's first two return values should be used to construct a sub-slice of
|
||||
// the complete, unpaginated slice. E.g. if the complete slice is s, then
|
||||
// s[from:to] is the desired page. Its third return value should be set as the
|
||||
// NextPageToken field of the RPC response.
|
||||
func PageBounds(pageSize int, pageToken string, length int) (from, to int, nextPageToken string, err error) {
|
||||
from, to = 0, length
|
||||
if pageToken != "" {
|
||||
from, err = strconv.Atoi(pageToken)
|
||||
if err != nil {
|
||||
return 0, 0, "", grpc.Errorf(codes.InvalidArgument, "bad page token: %v", err)
|
||||
}
|
||||
if from >= length {
|
||||
return length, length, "", nil
|
||||
}
|
||||
}
|
||||
if pageSize > 0 && from+pageSize < length {
|
||||
to = from + pageSize
|
||||
nextPageToken = strconv.Itoa(to)
|
||||
}
|
||||
return from, to, nextPageToken, nil
|
||||
}
|
||||
|
||||
44
vendor/cloud.google.com/go/internal/testutil/server_test.go
generated
vendored
44
vendor/cloud.google.com/go/internal/testutil/server_test.go
generated
vendored
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func TestNewServer(t *testing.T) {
|
||||
@@ -33,3 +34,46 @@ func TestNewServer(t *testing.T) {
|
||||
conn.Close()
|
||||
srv.Close()
|
||||
}
|
||||
|
||||
func TestPageBounds(t *testing.T) {
|
||||
const length = 10
|
||||
for _, test := range []struct {
|
||||
size int
|
||||
tok string
|
||||
wantFrom int
|
||||
wantTo int
|
||||
wantTok string
|
||||
}{
|
||||
{5, "",
|
||||
0, 5, "5"},
|
||||
{11, "",
|
||||
0, 10, ""},
|
||||
{5, "2",
|
||||
2, 7, "7"},
|
||||
{5, "8",
|
||||
8, 10, ""},
|
||||
{11, "8",
|
||||
8, 10, ""},
|
||||
{1, "11",
|
||||
10, 10, ""},
|
||||
} {
|
||||
gotFrom, gotTo, gotTok, err := PageBounds(test.size, test.tok, length)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := gotFrom, test.wantFrom; got != want {
|
||||
t.Errorf("%+v: from: got %d, want %d", test, got, want)
|
||||
}
|
||||
if got, want := gotTo, test.wantTo; got != want {
|
||||
t.Errorf("%+v: to: got %d, want %d", test, got, want)
|
||||
}
|
||||
if got, want := gotTok, test.wantTok; got != want {
|
||||
t.Errorf("%+v: got %q, want %q", test, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, _, err := PageBounds(4, "xyz", 5)
|
||||
if grpc.Code(err) != codes.InvalidArgument {
|
||||
t.Errorf("want invalid argument, got <%v>", err)
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
2
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
// Repo is the current version of the client libraries in this
|
||||
// repo. It should be a date in YYYYMMDD format.
|
||||
const Repo = "20170928"
|
||||
const Repo = "20180118"
|
||||
|
||||
// Go returns the Go runtime version. The returned string
|
||||
// has no whitespace.
|
||||
|
||||
Reference in New Issue
Block a user