go.uber.org/yarpc@v1.72.1/api/encoding/outbound_call_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 encoding
    22  
    23  import (
    24  	"context"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  	"go.uber.org/yarpc/api/transport"
    30  )
    31  
    32  func TestOutboundCallWriteToRequestAndRequestMeta(t *testing.T) {
    33  	tests := []struct {
    34  		desc        string
    35  		giveOptions []CallOption
    36  		giveRequest transport.Request
    37  		wantRequest transport.Request
    38  	}{
    39  		{
    40  			desc:        "no options",
    41  			giveOptions: []CallOption{},
    42  			giveRequest: transport.Request{
    43  				Caller:    "caller",
    44  				Service:   "service",
    45  				Encoding:  transport.Encoding("raw"),
    46  				Procedure: "hello",
    47  			},
    48  			wantRequest: transport.Request{
    49  				Caller:    "caller",
    50  				Service:   "service",
    51  				Encoding:  transport.Encoding("raw"),
    52  				Procedure: "hello",
    53  			},
    54  		},
    55  		{
    56  			desc: "headers",
    57  			giveOptions: []CallOption{
    58  				WithHeader("foo", "bar"),
    59  				WithHeader("baz", "qux"),
    60  			},
    61  			giveRequest: transport.Request{
    62  				Caller:    "caller",
    63  				Service:   "service",
    64  				Encoding:  transport.Encoding("raw"),
    65  				Procedure: "hello",
    66  			},
    67  			wantRequest: transport.Request{
    68  				Caller:    "caller",
    69  				Service:   "service",
    70  				Encoding:  transport.Encoding("raw"),
    71  				Procedure: "hello",
    72  				Headers:   transport.HeadersFromMap(map[string]string{"foo": "bar", "baz": "qux"}),
    73  			},
    74  		},
    75  		{
    76  			desc: "headers with duplicates",
    77  			giveOptions: []CallOption{
    78  				WithHeader("foo", "bar"),
    79  				WithHeader("baz", "qux"),
    80  				WithHeader("foo", "qux"),
    81  			},
    82  			wantRequest: transport.Request{
    83  				Headers: transport.HeadersFromMap(map[string]string{
    84  					"foo": "qux",
    85  					"baz": "qux",
    86  				}),
    87  			},
    88  		},
    89  		{
    90  			desc: "shard key",
    91  			giveOptions: []CallOption{
    92  				WithHeader("foo", "bar"),
    93  				WithShardKey("derp"),
    94  			},
    95  			wantRequest: transport.Request{
    96  				Headers:  transport.NewHeaders().With("foo", "bar"),
    97  				ShardKey: "derp",
    98  			},
    99  		},
   100  		{
   101  			desc: "routing key",
   102  			giveOptions: []CallOption{
   103  				WithShardKey("derp"),
   104  				WithRoutingKey("hello"),
   105  			},
   106  			wantRequest: transport.Request{
   107  				ShardKey:   "derp",
   108  				RoutingKey: "hello",
   109  			},
   110  		},
   111  		{
   112  			desc: "routing delegate",
   113  			giveOptions: []CallOption{
   114  				WithRoutingKey("hello"),
   115  				WithRoutingDelegate("zzz"),
   116  			},
   117  			wantRequest: transport.Request{
   118  				RoutingKey:      "hello",
   119  				RoutingDelegate: "zzz",
   120  			},
   121  		},
   122  	}
   123  
   124  	for _, tt := range tests {
   125  		t.Run(tt.desc+" regular", func(t *testing.T) {
   126  			call := NewOutboundCall(tt.giveOptions...)
   127  
   128  			request := tt.giveRequest
   129  			requestMeta := tt.giveRequest.ToRequestMeta()
   130  
   131  			_, err := call.WriteToRequest(context.Background(), &request)
   132  			if assert.NoError(t, err, tt.desc) {
   133  				assert.Equal(t, tt.wantRequest, request, tt.desc)
   134  			}
   135  
   136  			_, err = call.WriteToRequestMeta(context.Background(), requestMeta)
   137  			if assert.NoError(t, err, tt.desc) {
   138  				assert.Equal(t, tt.wantRequest.ToRequestMeta(), requestMeta, tt.desc)
   139  			}
   140  		})
   141  
   142  		t.Run(tt.desc+" streaming", func(t *testing.T) {
   143  			call, err := NewStreamOutboundCall(tt.giveOptions...)
   144  			require.NoError(t, err)
   145  
   146  			request := tt.giveRequest
   147  			requestMeta := tt.giveRequest.ToRequestMeta()
   148  
   149  			_, err = call.WriteToRequest(context.Background(), &request)
   150  			if assert.NoError(t, err, tt.desc) {
   151  				assert.Equal(t, tt.wantRequest, request, tt.desc)
   152  			}
   153  
   154  			_, err = call.WriteToRequestMeta(context.Background(), requestMeta)
   155  			if assert.NoError(t, err, tt.desc) {
   156  				assert.Equal(t, tt.wantRequest.ToRequestMeta(), requestMeta, tt.desc)
   157  			}
   158  		})
   159  	}
   160  }
   161  
   162  func TestOutboundCallReadFromResponse(t *testing.T) {
   163  	var headers map[string]string
   164  	call := NewOutboundCall(ResponseHeaders(&headers))
   165  	_, err := call.ReadFromResponse(context.Background(), &transport.Response{
   166  		Headers: transport.HeadersFromMap(map[string]string{
   167  			"hello":   "World",
   168  			"Foo":     "bar",
   169  			"success": "true",
   170  		}),
   171  	})
   172  
   173  	require.NoError(t, err)
   174  	assert.Equal(t, map[string]string{
   175  		"hello":   "World",
   176  		"foo":     "bar",
   177  		"success": "true",
   178  	}, headers)
   179  }
   180  
   181  func TestStreamOutboundCallCannotReadFromResponse(t *testing.T) {
   182  	var headers map[string]string
   183  	call, err := NewStreamOutboundCall(ResponseHeaders(&headers))
   184  	assert.Error(t, err)
   185  	assert.Contains(t, err.Error(), "code:invalid-argument")
   186  	assert.Contains(t, err.Error(), "response headers are not supported for streams")
   187  	assert.Nil(t, call)
   188  }