go.uber.org/yarpc@v1.72.1/internal/prototest/example/example.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 example
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  	"sync"
    27  	"time"
    28  
    29  	"go.uber.org/yarpc"
    30  	"go.uber.org/yarpc/api/transport"
    31  	"go.uber.org/yarpc/internal/prototest/examplepb"
    32  	"go.uber.org/yarpc/yarpcerrors"
    33  )
    34  
    35  const (
    36  	// FireDoneTimeout is how long fireDone will wait for both sending and receiving.
    37  	FireDoneTimeout = 3 * time.Second
    38  )
    39  
    40  var (
    41  	errRequestNil             = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request nil")
    42  	errRequestKeyNil          = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request key nil")
    43  	errRequestMessageNil      = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request message nil")
    44  	errRequestNumResponsesNil = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request num responses nil")
    45  )
    46  
    47  // KeyValueYARPCServer implements examplepb.KeyValueYARPCServer.
    48  type KeyValueYARPCServer struct {
    49  	sync.RWMutex
    50  	items map[string]string
    51  	// if next error is set it will be returned along with an empty response
    52  	// from any call to KeyValueYarpcServer, and then set to nil
    53  	nextError error
    54  }
    55  
    56  // NewKeyValueYARPCServer returns a new KeyValueYARPCServer.
    57  func NewKeyValueYARPCServer() *KeyValueYARPCServer {
    58  	return &KeyValueYARPCServer{sync.RWMutex{}, make(map[string]string), nil}
    59  }
    60  
    61  // GetValue implements GetValue.
    62  func (k *KeyValueYARPCServer) GetValue(ctx context.Context, request *examplepb.GetValueRequest) (*examplepb.GetValueResponse, error) {
    63  	if request == nil {
    64  		return nil, errRequestNil
    65  	}
    66  	if request.Key == "" {
    67  		return nil, errRequestKeyNil
    68  	}
    69  	k.RLock()
    70  	if value, ok := k.items[request.Key]; ok {
    71  		k.RUnlock()
    72  		var nextError error
    73  		k.Lock()
    74  		if k.nextError != nil {
    75  			nextError = k.nextError
    76  			k.nextError = nil
    77  		}
    78  		k.Unlock()
    79  		return &examplepb.GetValueResponse{Value: value}, nextError
    80  	}
    81  	k.RUnlock()
    82  	return nil, yarpcerrors.Newf(yarpcerrors.CodeNotFound, request.Key)
    83  }
    84  
    85  // SetValue implements SetValue.
    86  func (k *KeyValueYARPCServer) SetValue(ctx context.Context, request *examplepb.SetValueRequest) (*examplepb.SetValueResponse, error) {
    87  	call := yarpc.CallFromContext(ctx)
    88  	if val := call.Header("test-header"); val != "" {
    89  		_ = call.WriteResponseHeader("test-header", val)
    90  	}
    91  	if request == nil {
    92  		return nil, errRequestNil
    93  	}
    94  	if request.Key == "" {
    95  		return nil, errRequestKeyNil
    96  	}
    97  	k.Lock()
    98  	if request.Value == "" {
    99  		delete(k.items, request.Key)
   100  	} else {
   101  		k.items[request.Key] = request.Value
   102  	}
   103  	var nextError error
   104  	if k.nextError != nil {
   105  		nextError = k.nextError
   106  		k.nextError = nil
   107  	}
   108  	k.Unlock()
   109  	return nil, nextError
   110  }
   111  
   112  // SetNextError sets the error to return on the next call to KeyValueYARPCServer.
   113  func (k *KeyValueYARPCServer) SetNextError(err error) {
   114  	k.Lock()
   115  	defer k.Unlock()
   116  	k.nextError = err
   117  }
   118  
   119  // FooYARPCServer implements examplepb.FooYARPCServer.
   120  type FooYARPCServer struct {
   121  	expectedHeaders transport.Headers
   122  }
   123  
   124  // NewFooYARPCServer returns a new FooYARPCServer.
   125  func NewFooYARPCServer(expectedHeaders transport.Headers) *FooYARPCServer {
   126  	return &FooYARPCServer{
   127  		expectedHeaders: expectedHeaders,
   128  	}
   129  }
   130  
   131  // EchoOut reads from a stream and echos all requests in the response.
   132  func (f *FooYARPCServer) EchoOut(server examplepb.FooServiceEchoOutYARPCServer) (*examplepb.EchoOutResponse, error) {
   133  	var allMessages []string
   134  	call := yarpc.CallFromContext(server.Context())
   135  	for k, v := range f.expectedHeaders.Items() {
   136  		if call.Header(k) != v {
   137  			return nil, yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v)
   138  		}
   139  	}
   140  	for request, err := server.Recv(); err != io.EOF; request, err = server.Recv() {
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		if request == nil {
   145  			return nil, errRequestNil
   146  		}
   147  		if request.Message == "" {
   148  			return nil, errRequestMessageNil
   149  		}
   150  		allMessages = append(allMessages, request.Message)
   151  	}
   152  	return &examplepb.EchoOutResponse{
   153  		AllMessages: allMessages,
   154  	}, nil
   155  }
   156  
   157  // EchoIn echos a series of requests back on a stream.
   158  func (f *FooYARPCServer) EchoIn(request *examplepb.EchoInRequest, server examplepb.FooServiceEchoInYARPCServer) error {
   159  	if request == nil {
   160  		return errRequestNil
   161  	}
   162  	if request.Message == "" {
   163  		return errRequestMessageNil
   164  	}
   165  	if request.NumResponses == 0 {
   166  		return errRequestNumResponsesNil
   167  	}
   168  	call := yarpc.CallFromContext(server.Context())
   169  	for k, v := range f.expectedHeaders.Items() {
   170  		if call.Header(k) != v {
   171  			return yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v)
   172  		}
   173  	}
   174  	for i := 0; i < int(request.NumResponses); i++ {
   175  		if err := server.Send(&examplepb.EchoInResponse{Message: request.Message}); err != nil {
   176  			return err
   177  		}
   178  	}
   179  	return nil
   180  }
   181  
   182  // EchoBoth immediately echos a request back to the client.
   183  func (f *FooYARPCServer) EchoBoth(server examplepb.FooServiceEchoBothYARPCServer) error {
   184  	call := yarpc.CallFromContext(server.Context())
   185  	for k, v := range f.expectedHeaders.Items() {
   186  		if call.Header(k) != v {
   187  			return yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v)
   188  		}
   189  	}
   190  	for request, err := server.Recv(); err != io.EOF; request, err = server.Recv() {
   191  		if err != nil {
   192  			return err
   193  		}
   194  		if request == nil {
   195  			return errRequestNil
   196  		}
   197  		if request.Message == "" {
   198  			return errRequestMessageNil
   199  		}
   200  		if request.NumResponses == 0 {
   201  			return errRequestNumResponsesNil
   202  		}
   203  		for i := 0; i < int(request.NumResponses); i++ {
   204  			if err := server.Send(&examplepb.EchoBothResponse{Message: request.Message}); err != nil {
   205  				return err
   206  			}
   207  		}
   208  	}
   209  	return nil
   210  }