github.com/go-graphite/carbonapi@v0.17.0/zipper/dummy/dummy.go (about)

     1  package dummy
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/ansel1/merry"
    10  
    11  	"github.com/go-graphite/carbonapi/zipper/types"
    12  	protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
    13  )
    14  
    15  type FetchResponse struct {
    16  	Response *protov3.MultiFetchResponse
    17  	Stats    *types.Stats
    18  	Errors   merry.Error
    19  }
    20  
    21  type FindResponse struct {
    22  	Response *protov3.MultiGlobResponse
    23  	Stats    *types.Stats
    24  	Errors   merry.Error
    25  }
    26  
    27  type InfoResponse struct {
    28  	Response *protov3.ZipperInfoResponse
    29  	Stats    *types.Stats
    30  	Errors   merry.Error
    31  }
    32  
    33  type ListResponse struct {
    34  	Response *protov3.ListMetricsResponse
    35  	Stats    *types.Stats
    36  	Errors   merry.Error
    37  }
    38  
    39  type StatsResponse struct {
    40  	Response *protov3.MetricDetailsResponse
    41  	Stats    *types.Stats
    42  	Errors   merry.Error
    43  }
    44  
    45  type ProbeResponse struct {
    46  	Response []string
    47  	Errors   merry.Error
    48  }
    49  
    50  type DummyClient struct {
    51  	name                 string
    52  	backends             []string
    53  	maxMetricsPerRequest int
    54  
    55  	fetchResponses    map[string]FetchResponse
    56  	findResponses     map[string]FindResponse
    57  	infoResponses     map[string]InfoResponse
    58  	statsResponses    map[string]StatsResponse
    59  	tagNameResponse   []string
    60  	tagValuesResponse []string
    61  	probeResponses    ProbeResponse
    62  	alwaysTimeout     time.Duration
    63  }
    64  
    65  func (d *DummyClient) Children() []types.BackendServer {
    66  	return []types.BackendServer{d}
    67  }
    68  
    69  func NewDummyClient(name string, backends []string, maxMetricsPerRequest int) *DummyClient {
    70  	return &DummyClient{
    71  		name:                 name,
    72  		backends:             backends,
    73  		maxMetricsPerRequest: maxMetricsPerRequest,
    74  
    75  		fetchResponses: make(map[string]FetchResponse),
    76  		findResponses:  make(map[string]FindResponse),
    77  		infoResponses:  make(map[string]InfoResponse),
    78  		statsResponses: make(map[string]StatsResponse),
    79  		alwaysTimeout:  0,
    80  	}
    81  }
    82  
    83  func NewDummyClientWithTimeout(name string, backends []string, maxMetricsPerRequest int, alwaysTimeout time.Duration) *DummyClient {
    84  	return &DummyClient{
    85  		name:                 name,
    86  		backends:             backends,
    87  		maxMetricsPerRequest: maxMetricsPerRequest,
    88  
    89  		fetchResponses: make(map[string]FetchResponse),
    90  		findResponses:  make(map[string]FindResponse),
    91  		infoResponses:  make(map[string]InfoResponse),
    92  		statsResponses: make(map[string]StatsResponse),
    93  		alwaysTimeout:  alwaysTimeout,
    94  	}
    95  }
    96  
    97  func (c *DummyClient) Name() string {
    98  	return c.name
    99  }
   100  
   101  func (c *DummyClient) Backends() []string {
   102  	return c.backends
   103  }
   104  
   105  func (c *DummyClient) MaxMetricsPerRequest() int {
   106  	return c.maxMetricsPerRequest
   107  }
   108  
   109  func fetchRequestToKey(request *protov3.MultiFetchRequest) string {
   110  	var key []byte
   111  	for _, r := range request.Metrics {
   112  		key = append(key, []byte("&"+r.Name+"&start="+strconv.FormatUint(uint64(r.StartTime), 10)+"&stop="+strconv.FormatUint(uint64(r.StopTime), 10)+"\n")...)
   113  	}
   114  
   115  	return string(key)
   116  }
   117  
   118  func (c *DummyClient) AddFetchResponse(request *protov3.MultiFetchRequest, response *protov3.MultiFetchResponse, stats *types.Stats, errors merry.Error) {
   119  	key := fetchRequestToKey(request)
   120  	c.fetchResponses[key] = FetchResponse{response, stats, errors}
   121  
   122  	for _, m := range request.Metrics {
   123  		findRequest := protov3.MultiGlobRequest{
   124  			Metrics: []string{
   125  				m.Name,
   126  			},
   127  		}
   128  		findResponse := protov3.MultiGlobResponse{
   129  			Metrics: []protov3.GlobResponse{
   130  				{
   131  					Name: m.Name,
   132  					Matches: []protov3.GlobMatch{
   133  						{
   134  							Path:   m.Name,
   135  							IsLeaf: true,
   136  						},
   137  					},
   138  				},
   139  			},
   140  		}
   141  		c.AddFindResponse(&findRequest, &findResponse, &types.Stats{}, errors)
   142  	}
   143  }
   144  
   145  func (c *DummyClient) Fetch(ctx context.Context, request *protov3.MultiFetchRequest) (*protov3.MultiFetchResponse, *types.Stats, merry.Error) {
   146  	if c.alwaysTimeout > 0 {
   147  		time.Sleep(c.alwaysTimeout)
   148  		return nil, nil, types.ErrTimeoutExceeded
   149  	}
   150  	select {
   151  	case <-ctx.Done():
   152  		return nil, nil, types.ErrTimeoutExceeded
   153  	default:
   154  	}
   155  
   156  	key := fetchRequestToKey(request)
   157  	r, ok := c.fetchResponses[key]
   158  	if ok {
   159  		return r.Response, r.Stats, r.Errors
   160  	}
   161  
   162  	return nil, nil, nil
   163  }
   164  
   165  func findRequestToKey(request *protov3.MultiGlobRequest) string {
   166  	return strings.Join(request.Metrics, "&")
   167  }
   168  
   169  func (c *DummyClient) AddFindResponse(request *protov3.MultiGlobRequest, response *protov3.MultiGlobResponse, stats *types.Stats, errors merry.Error) {
   170  	key := findRequestToKey(request)
   171  	c.findResponses[key] = FindResponse{response, stats, errors}
   172  }
   173  
   174  func (c *DummyClient) Find(ctx context.Context, request *protov3.MultiGlobRequest) (*protov3.MultiGlobResponse, *types.Stats, merry.Error) {
   175  	if c.alwaysTimeout > 0 {
   176  		time.Sleep(c.alwaysTimeout)
   177  		return nil, nil, types.ErrTimeoutExceeded
   178  	}
   179  	select {
   180  	case <-ctx.Done():
   181  		return nil, nil, types.ErrTimeoutExceeded
   182  	default:
   183  	}
   184  
   185  	r, ok := c.findResponses[findRequestToKey(request)]
   186  	if ok {
   187  		return r.Response, r.Stats, r.Errors
   188  	}
   189  	return nil, nil, nil
   190  }
   191  
   192  func (c *DummyClient) Info(ctx context.Context, request *protov3.MultiMetricsInfoRequest) (*protov3.ZipperInfoResponse, *types.Stats, merry.Error) {
   193  	return nil, nil, types.ErrNotImplementedYet
   194  }
   195  
   196  func (c *DummyClient) List(ctx context.Context) (*protov3.ListMetricsResponse, *types.Stats, merry.Error) {
   197  	return nil, nil, types.ErrNotImplementedYet
   198  }
   199  
   200  func (c *DummyClient) Stats(ctx context.Context) (*protov3.MetricDetailsResponse, *types.Stats, merry.Error) {
   201  	return nil, nil, types.ErrNotImplementedYet
   202  }
   203  
   204  func (c *DummyClient) SetTLDResponse(response ProbeResponse) {
   205  	c.probeResponses = response
   206  }
   207  
   208  func (c *DummyClient) SetTagNamesResponse(response []string) {
   209  	c.tagNameResponse = response
   210  }
   211  
   212  func (c *DummyClient) TagNames(ctx context.Context, query string, limit int64) ([]string, merry.Error) {
   213  	return c.tagNameResponse, nil
   214  }
   215  
   216  func (c *DummyClient) SetTagValuesResponse(response []string) {
   217  	c.tagValuesResponse = response
   218  }
   219  
   220  func (c *DummyClient) TagValues(ctx context.Context, query string, limit int64) ([]string, merry.Error) {
   221  	return c.tagNameResponse, nil
   222  }
   223  
   224  func (c *DummyClient) ProbeTLDs(ctx context.Context) ([]string, merry.Error) {
   225  	return c.probeResponses.Response, c.probeResponses.Errors
   226  }