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:
Alexander Neumann
2018-01-23 19:40:42 +01:00
parent b63de7c798
commit 2b39f9f4b2
3435 changed files with 1318042 additions and 315692 deletions

54
vendor/cloud.google.com/go/internal/annotate.go generated vendored Normal file
View 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
View 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)
}
}

View File

@@ -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
}

View File

@@ -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

View 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")
}
}

View 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)
}
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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
// }

View File

@@ -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
}

View File

@@ -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,
}

View File

@@ -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 {}

View File

@@ -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,
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
View 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.

View 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
View 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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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.