gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/client/mock/mock.go (about)

     1  // Package mock provides a mock client for testing
     2  package mock
     3  
     4  import (
     5  	"context"
     6  	"fmt"
     7  	"reflect"
     8  	"sync"
     9  
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/client"
    11  	"gitee.com/liuxuezhan/go-micro-v1.18.0/errors"
    12  )
    13  
    14  var (
    15  	_ client.Client = NewClient()
    16  )
    17  
    18  type MockResponse struct {
    19  	Endpoint string
    20  	Response interface{}
    21  	Error    error
    22  }
    23  
    24  type MockClient struct {
    25  	Client client.Client
    26  	Opts   client.Options
    27  
    28  	sync.Mutex
    29  	Response map[string][]MockResponse
    30  }
    31  
    32  func (m *MockClient) Init(opts ...client.Option) error {
    33  	m.Lock()
    34  	defer m.Unlock()
    35  
    36  	for _, opt := range opts {
    37  		opt(&m.Opts)
    38  	}
    39  
    40  	r, ok := fromContext(m.Opts.Context)
    41  	if !ok {
    42  		r = make(map[string][]MockResponse)
    43  	}
    44  	m.Response = r
    45  
    46  	return nil
    47  }
    48  
    49  func (m *MockClient) Options() client.Options {
    50  	return m.Opts
    51  }
    52  
    53  func (m *MockClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message {
    54  	return m.Client.NewMessage(topic, msg, opts...)
    55  }
    56  
    57  func (m *MockClient) NewRequest(service, endpoint string, req interface{}, reqOpts ...client.RequestOption) client.Request {
    58  	return m.Client.NewRequest(service, endpoint, req, reqOpts...)
    59  }
    60  
    61  func (m *MockClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    62  	m.Lock()
    63  	defer m.Unlock()
    64  
    65  	response, ok := m.Response[req.Service()]
    66  	if !ok {
    67  		return errors.NotFound("go.micro.client.mock", "service not found")
    68  	}
    69  
    70  	for _, r := range response {
    71  		if r.Endpoint != req.Endpoint() {
    72  			continue
    73  		}
    74  
    75  		if r.Error != nil {
    76  			return r.Error
    77  		}
    78  
    79  		v := reflect.ValueOf(rsp)
    80  
    81  		if t := reflect.TypeOf(rsp); t.Kind() == reflect.Ptr {
    82  			v = reflect.Indirect(v)
    83  		}
    84  		response := r.Response
    85  		if t := reflect.TypeOf(r.Response); t.Kind() == reflect.Func {
    86  			var request []reflect.Value
    87  			if t.NumIn() == 1 {
    88  				request = append(request, reflect.ValueOf(req.Body()))
    89  			}
    90  			response = reflect.ValueOf(r.Response).Call(request)[0].Interface()
    91  		}
    92  
    93  		v.Set(reflect.ValueOf(response))
    94  
    95  		return nil
    96  	}
    97  
    98  	return fmt.Errorf("rpc: can't find service %s", req.Endpoint())
    99  }
   100  
   101  func (m *MockClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
   102  	m.Lock()
   103  	defer m.Unlock()
   104  
   105  	// TODO: mock stream
   106  	return nil, nil
   107  }
   108  
   109  func (m *MockClient) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
   110  	return nil
   111  }
   112  
   113  func (m *MockClient) String() string {
   114  	return "mock"
   115  }
   116  
   117  func NewClient(opts ...client.Option) *MockClient {
   118  	options := client.Options{
   119  		Context: context.TODO(),
   120  	}
   121  
   122  	for _, opt := range opts {
   123  		opt(&options)
   124  	}
   125  
   126  	r, ok := fromContext(options.Context)
   127  	if !ok {
   128  		r = make(map[string][]MockResponse)
   129  	}
   130  
   131  	return &MockClient{
   132  		Client:   client.DefaultClient,
   133  		Opts:     options,
   134  		Response: r,
   135  	}
   136  }