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

32
vendor/cloud.google.com/go/rpcreplay/Makefile generated vendored Normal file
View File

@@ -0,0 +1,32 @@
# 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

108
vendor/cloud.google.com/go/rpcreplay/doc.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
// 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 you capture the calls of a test that runs against a real
service, you have an "automatic mock" that can be replayed against the same test,
yielding a unit test that is fast and flake-free.
This package is EXPERIMENTAL and subject to change without notice.
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 is 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, such
as the current time, or 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/rpcreplay"

47
vendor/cloud.google.com/go/rpcreplay/example_test.go generated vendored Normal file
View File

@@ -0,0 +1,47 @@
// 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/rpcreplay/fake_test.go generated vendored Normal file
View File

@@ -0,0 +1,121 @@
// 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/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

@@ -0,0 +1,454 @@
// 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

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

@@ -0,0 +1,170 @@
// 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

@@ -0,0 +1,71 @@
// 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/rpcreplay/rpcreplay.go generated vendored Normal file
View File

@@ -0,0 +1,689 @@
// 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/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/rpcreplay/rpcreplay_test.go generated vendored Normal file
View File

@@ -0,0 +1,362 @@
// 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"
"cloud.google.com/go/internal/testutil"
ipb "cloud.google.com/go/rpcreplay/proto/intstore"
rpb "cloud.google.com/go/rpcreplay/proto/rpcreplay"
"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)
}
}