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 }