testutils/call.go (110 lines of code) (raw):
// Copyright (c) 2015 Uber Technologies, Inc.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package testutils
import (
"testing"
"time"
"github.com/uber/tchannel-go"
"github.com/uber/tchannel-go/relay"
"github.com/uber/tchannel-go/testutils/thriftarg2test"
"github.com/uber/tchannel-go/thrift/arg2"
)
// FakeIncomingCall implements IncomingCall interface.
// Note: the F suffix for the fields is to clash with the method name.
type FakeIncomingCall struct {
// CallerNameF is the calling service's name.
CallerNameF string
// ShardKeyF is the intended destination for this call.
ShardKeyF string
// RemotePeerF is the calling service's peer info.
RemotePeerF tchannel.PeerInfo
// LocalPeerF is the local service's peer info.
LocalPeerF tchannel.LocalPeerInfo
// RoutingKeyF is the routing key.
RoutingKeyF string
// RoutingDelegateF is the routing delegate.
RoutingDelegateF string
}
// CallerName returns the caller name as specified in the fake call.
func (f *FakeIncomingCall) CallerName() string {
return f.CallerNameF
}
// ShardKey returns the shard key as specified in the fake call.
func (f *FakeIncomingCall) ShardKey() string {
return f.ShardKeyF
}
// RoutingKey returns the routing delegate as specified in the fake call.
func (f *FakeIncomingCall) RoutingKey() string {
return f.RoutingKeyF
}
// RoutingDelegate returns the routing delegate as specified in the fake call.
func (f *FakeIncomingCall) RoutingDelegate() string {
return f.RoutingDelegateF
}
// LocalPeer returns the local peer information for this call.
func (f *FakeIncomingCall) LocalPeer() tchannel.LocalPeerInfo {
return f.LocalPeerF
}
// RemotePeer returns the remote peer information for this call.
func (f *FakeIncomingCall) RemotePeer() tchannel.PeerInfo {
return f.RemotePeerF
}
// CallOptions returns the incoming call options suitable for proxying a request.
func (f *FakeIncomingCall) CallOptions() *tchannel.CallOptions {
return &tchannel.CallOptions{
ShardKey: f.ShardKey(),
RoutingKey: f.RoutingKey(),
RoutingDelegate: f.RoutingDelegate(),
}
}
// NewIncomingCall creates an incoming call for tests.
func NewIncomingCall(callerName string) tchannel.IncomingCall {
return &FakeIncomingCall{CallerNameF: callerName}
}
// FakeCallFrame is a stub implementation of the CallFrame interface.
type FakeCallFrame struct {
tb testing.TB
TTLF time.Duration
ServiceF, MethodF, CallerF, RoutingKeyF, RoutingDelegateF string
Arg2StartOffsetVal, Arg2EndOffsetVal int
IsArg2Fragmented bool
arg2KVIterator arg2.KeyValIterator
hasArg2KVIterator error
Arg2Appends []relay.KeyVal
}
var _ relay.CallFrame = &FakeCallFrame{}
// TTL returns the TTL field.
func (f *FakeCallFrame) TTL() time.Duration {
return f.TTLF
}
// Service returns the service name field.
func (f *FakeCallFrame) Service() []byte {
return []byte(f.ServiceF)
}
// Method returns the method field.
func (f *FakeCallFrame) Method() []byte {
return []byte(f.MethodF)
}
// Caller returns the caller field.
func (f *FakeCallFrame) Caller() []byte {
return []byte(f.CallerF)
}
// RoutingKey returns the routing delegate field.
func (f *FakeCallFrame) RoutingKey() []byte {
return []byte(f.RoutingKeyF)
}
// RoutingDelegate returns the routing delegate field.
func (f *FakeCallFrame) RoutingDelegate() []byte {
return []byte(f.RoutingDelegateF)
}
// Arg2StartOffset returns the offset from start of payload to
// the beginning of Arg2.
func (f *FakeCallFrame) Arg2StartOffset() int {
return f.Arg2StartOffsetVal
}
// Arg2EndOffset returns the offset from start of payload to the end
// of Arg2 and whether Arg2 is fragmented.
func (f *FakeCallFrame) Arg2EndOffset() (int, bool) {
return f.Arg2EndOffsetVal, f.IsArg2Fragmented
}
// Arg2Iterator returns the iterator for reading Arg2 key value pair
// of TChannel-Thrift Arg Scheme.
func (f *FakeCallFrame) Arg2Iterator() (arg2.KeyValIterator, error) {
return f.arg2KVIterator, f.hasArg2KVIterator
}
// Arg2Append appends a key value pair to Arg2
func (f *FakeCallFrame) Arg2Append(key, val []byte) {
f.Arg2Appends = append(f.Arg2Appends, relay.KeyVal{Key: key, Val: val})
}
// CopyCallFrame copies the relay.CallFrame and returns a FakeCallFrame with
// corresponding values
func CopyCallFrame(f relay.CallFrame) *FakeCallFrame {
endOffset, hasMore := f.Arg2EndOffset()
copyIterator, err := copyThriftArg2KVIterator(f)
return &FakeCallFrame{
TTLF: f.TTL(),
ServiceF: string(f.Service()),
MethodF: string(f.Method()),
CallerF: string(f.Caller()),
RoutingKeyF: string(f.RoutingKey()),
RoutingDelegateF: string(f.RoutingDelegate()),
Arg2StartOffsetVal: f.Arg2StartOffset(),
Arg2EndOffsetVal: endOffset,
IsArg2Fragmented: hasMore,
arg2KVIterator: copyIterator,
hasArg2KVIterator: err,
}
}
// copyThriftArg2KVIterator uses the CallFrame Arg2Iterator to make a
// deep-copy KeyValIterator.
func copyThriftArg2KVIterator(f relay.CallFrame) (arg2.KeyValIterator, error) {
kv := make(map[string]string)
for iter, err := f.Arg2Iterator(); err == nil; iter, err = iter.Next() {
kv[string(iter.Key())] = string(iter.Value())
}
return arg2.NewKeyValIterator(thriftarg2test.BuildKVBuffer(kv))
}