go.uber.org/yarpc@v1.72.1/encoding/raw/inbound_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 raw 22 23 import ( 24 "context" 25 "errors" 26 "fmt" 27 "testing" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 "github.com/uber/tchannel-go/testutils/testreader" 32 "go.uber.org/yarpc" 33 "go.uber.org/yarpc/api/transport" 34 "go.uber.org/yarpc/api/transport/transporttest" 35 "go.uber.org/yarpc/internal/testtime" 36 ) 37 38 func TestRawHandler(t *testing.T) { 39 // handler to use for test cases where the handler should not be called 40 handlerNotCalled := 41 func(ctx context.Context, body []byte) ([]byte, error) { 42 t.Errorf("unexpected call handle(%v)", body) 43 return nil, fmt.Errorf("unexpected call handle(%v)", body) 44 } 45 46 tests := []struct { 47 procedure string 48 headers transport.Headers 49 bodyChunks [][]byte 50 handler UnaryHandler 51 52 wantErr string 53 wantHeaders transport.Headers 54 wantBody []byte 55 }{ 56 { 57 procedure: "foo", 58 bodyChunks: [][]byte{ 59 {1, 2, 3}, 60 {4, 5, 6}, 61 }, 62 handler: func(ctx context.Context, body []byte) ([]byte, error) { 63 assert.Equal(t, "foo", yarpc.CallFromContext(ctx).Procedure()) 64 assert.Equal(t, []byte{1, 2, 3, 4, 5, 6}, body) 65 return []byte("hello"), nil 66 }, 67 wantBody: []byte("hello"), 68 }, 69 { 70 procedure: "foo", 71 bodyChunks: [][]byte{ 72 {1, 2, 3}, 73 {4, 5, 6}, 74 }, 75 handler: func(ctx context.Context, body []byte) ([]byte, error) { 76 assert.Equal(t, "foo", yarpc.CallFromContext(ctx).Procedure()) 77 assert.Equal(t, []byte{1, 2, 3, 4, 5, 6}, body) 78 return []byte("hello"), errors.New("bar") 79 }, 80 wantBody: []byte("hello"), 81 wantErr: "bar", 82 }, 83 { 84 procedure: "bar", 85 bodyChunks: [][]byte{ 86 {1, 2, 3}, 87 nil, // triggers a read error 88 {4, 5, 6}, 89 }, 90 handler: handlerNotCalled, 91 wantErr: "error set by user", 92 // TODO consistent error messages between languages 93 }, 94 { 95 procedure: "baz", 96 bodyChunks: [][]byte{}, 97 handler: func(ctx context.Context, body []byte) ([]byte, error) { 98 assert.Equal(t, []byte{}, body) 99 return nil, fmt.Errorf("great sadness") 100 }, 101 wantErr: "great sadness", 102 }, 103 { 104 procedure: "responseHeaders", 105 bodyChunks: [][]byte{}, 106 handler: func(ctx context.Context, body []byte) ([]byte, error) { 107 require.NoError(t, yarpc.CallFromContext(ctx).WriteResponseHeader("hello", "world")) 108 return []byte{}, nil 109 }, 110 wantHeaders: transport.NewHeaders().With("hello", "world"), 111 }, 112 } 113 114 for _, tt := range tests { 115 handler := rawUnaryHandler{tt.handler} 116 resw := new(transporttest.FakeResponseWriter) 117 118 writer, chunkReader := testreader.ChunkReader() 119 for _, chunk := range tt.bodyChunks { 120 writer <- chunk 121 } 122 close(writer) 123 124 ctx, cancel := context.WithTimeout(context.Background(), testtime.Second) 125 defer cancel() 126 127 err := handler.Handle(ctx, &transport.Request{ 128 Procedure: tt.procedure, 129 Headers: tt.headers, 130 Encoding: "raw", 131 Body: chunkReader, 132 }, resw) 133 134 if tt.wantErr != "" { 135 if assert.Error(t, err) { 136 assert.Equal(t, err.Error(), tt.wantErr) 137 } 138 } else { 139 assert.NoError(t, err) 140 } 141 assert.Equal(t, tt.wantHeaders, resw.Headers) 142 if tt.wantBody != nil { 143 assert.Equal(t, tt.wantBody, resw.Body.Bytes(), 144 "body does not match for %s", tt.procedure) 145 } 146 } 147 }