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 }