go.uber.org/yarpc@v1.72.1/transport/tchannel/tchannel_utils_test.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package tchannel
    22  
    23  import (
    24  	"bytes"
    25  	"errors"
    26  	"io/ioutil"
    27  
    28  	"github.com/uber/tchannel-go"
    29  )
    30  
    31  func readArgs(r tchannel.ArgReadable) (arg2, arg3 []byte, err error) {
    32  	err = tchannel.NewArgReader(r.Arg2Reader()).Read(&arg2)
    33  	if err != nil {
    34  		return
    35  	}
    36  
    37  	err = tchannel.NewArgReader(r.Arg3Reader()).Read(&arg3)
    38  	return
    39  }
    40  
    41  func writeArgs(w tchannel.ArgWritable, arg2, arg3 []byte) error {
    42  	if err := tchannel.NewArgWriter(w.Arg2Writer()).Write(arg2); err != nil {
    43  		return err
    44  	}
    45  
    46  	return tchannel.NewArgWriter(w.Arg3Writer()).Write(arg3)
    47  }
    48  
    49  // This file provides utilities to help test TChannel behavior used by
    50  // multiple tests.
    51  
    52  // bufferArgWriter is a Buffer that satisfies the tchannel.ArgWriter
    53  // interface.
    54  type bufferArgWriter struct{ bytes.Buffer }
    55  
    56  func newBufferArgWriter() *bufferArgWriter {
    57  	return new(bufferArgWriter)
    58  }
    59  
    60  func (w *bufferArgWriter) Close() error { return nil }
    61  func (w *bufferArgWriter) Flush() error { return nil }
    62  
    63  // fakeInboundCall is a fake inboundCall that uses a responseRecorder to
    64  // record responses.
    65  //
    66  // Provide nil for arg2 or arg3 to get Arg2Reader or Arg3Reader to fail.
    67  type fakeInboundCall struct {
    68  	service         string
    69  	caller          string
    70  	method          string
    71  	shardkey        string
    72  	routingkey      string
    73  	routingdelegate string
    74  	format          tchannel.Format
    75  	arg2, arg3      []byte
    76  	resp            inboundCallResponse
    77  }
    78  
    79  func (i *fakeInboundCall) ServiceName() string           { return i.service }
    80  func (i *fakeInboundCall) CallerName() string            { return i.caller }
    81  func (i *fakeInboundCall) MethodString() string          { return i.method }
    82  func (i *fakeInboundCall) ShardKey() string              { return i.shardkey }
    83  func (i *fakeInboundCall) RoutingKey() string            { return i.routingkey }
    84  func (i *fakeInboundCall) RoutingDelegate() string       { return i.routingdelegate }
    85  func (i *fakeInboundCall) Format() tchannel.Format       { return i.format }
    86  func (i *fakeInboundCall) Response() inboundCallResponse { return i.resp }
    87  
    88  func (i *fakeInboundCall) Arg2Reader() (tchannel.ArgReader, error) {
    89  	if i.arg2 == nil {
    90  		return nil, errors.New("no arg2 provided")
    91  	}
    92  	return ioutil.NopCloser(bytes.NewReader(i.arg2)), nil
    93  }
    94  
    95  func (i *fakeInboundCall) Arg3Reader() (tchannel.ArgReader, error) {
    96  	if i.arg3 == nil {
    97  		return nil, errors.New("no arg3 provided")
    98  	}
    99  	return ioutil.NopCloser(bytes.NewReader(i.arg3)), nil
   100  }
   101  
   102  // recorder wraps the inboundCallResponse interface to mock errors from responseRecorder's
   103  // methods during testing
   104  type recorder interface {
   105  	inboundCallResponse
   106  	SystemError() error
   107  }
   108  
   109  // responseRecorder is a inboundCallResponse that records whatever is written
   110  // to it.
   111  //
   112  // The recorder will throw an error if arg2 or arg3 are set to nil.
   113  type responseRecorder struct {
   114  	arg2, arg3       *bufferArgWriter
   115  	systemErr        error
   116  	applicationError bool
   117  	blackholed       bool
   118  }
   119  
   120  func newResponseRecorder() *responseRecorder {
   121  	return &responseRecorder{
   122  		arg2: newBufferArgWriter(),
   123  		arg3: newBufferArgWriter(),
   124  	}
   125  }
   126  
   127  func (rr *responseRecorder) Arg2Writer() (tchannel.ArgWriter, error) {
   128  	if rr.arg2 == nil {
   129  		return nil, errors.New("no arg2 provided")
   130  	}
   131  	return rr.arg2, nil
   132  }
   133  
   134  func (rr *responseRecorder) Arg3Writer() (tchannel.ArgWriter, error) {
   135  	if rr.arg3 == nil {
   136  		return nil, errors.New("no arg3 provided")
   137  	}
   138  	return rr.arg3, nil
   139  }
   140  
   141  func (rr *responseRecorder) SendSystemError(err error) error {
   142  	rr.systemErr = err
   143  	return nil
   144  }
   145  
   146  func (rr *responseRecorder) SystemError() error {
   147  	return rr.systemErr
   148  }
   149  
   150  func (rr *responseRecorder) SetApplicationError() error {
   151  	rr.applicationError = true
   152  	return nil
   153  }
   154  
   155  func (rr *responseRecorder) Blackhole() {
   156  	rr.blackholed = true
   157  }
   158  
   159  // faultyResponseRecorder mocks a SendSystemError to test logging behaviour
   160  // inside tchannel.Handle
   161  type faultyResponseRecorder struct{ responseRecorder }
   162  
   163  func newFaultyResponseRecorder() recorder {
   164  	return &faultyResponseRecorder{}
   165  }
   166  
   167  func (fr *faultyResponseRecorder) SendSystemError(err error) error {
   168  	fr.systemErr = err
   169  	return errors.New("SendSystemError failure")
   170  }
   171  
   172  // faultyHandlerWriter mocks a responseWriter.Close() error to test logging behaviour
   173  // inside tchannel.Handle.
   174  type faultyHandlerWriter struct{ handlerWriter }
   175  
   176  func newFaultyHandlerWriter(response inboundCallResponse, format tchannel.Format, headerCase headerCase) responseWriter {
   177  	return &faultyHandlerWriter{}
   178  }
   179  
   180  func (frw *faultyHandlerWriter) Close() error {
   181  	return errors.New("faultyHandlerWriter failed to close")
   182  }