github.com/grafana/synthetic-monitoring-agent@v0.64.2/internal/pusher/v2/errors_test.go (about) 1 package v2 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/grafana/synthetic-monitoring-agent/internal/pkg/prom" 12 ) 13 14 func TestParsePushError(t *testing.T) { 15 for title, tc := range map[string]struct { 16 input error 17 expected error 18 code int 19 }{ 20 "no error": { 21 input: nil, 22 expected: pushError{ 23 kind: errKindNoError, 24 }, 25 code: http.StatusOK, 26 }, 27 28 "context canceled": { 29 input: context.Canceled, 30 expected: pushError{ 31 kind: errKindTerminated, 32 }, 33 code: 0, 34 }, 35 36 "context deadline exceeded": { 37 input: context.DeadlineExceeded, 38 expected: pushError{ 39 kind: errKindNetwork, 40 }, 41 code: 0, 42 }, 43 44 "other error is network": { 45 input: errors.New("something is wrong"), 46 expected: pushError{ 47 kind: errKindNetwork, 48 }, 49 code: 0, 50 }, 51 52 "500 errors are temporary": { 53 input: &prom.HttpError{ 54 StatusCode: 500, 55 Status: "Internal Server Error", 56 Err: errors.New(`something is wrong`), 57 }, 58 expected: pushError{ 59 kind: errKindNetwork, 60 }, 61 code: 500, 62 }, 63 64 "500 from grafana instance": { 65 input: &prom.HttpError{ 66 StatusCode: 500, 67 Status: "Internal Server Error", 68 Err: errors.New(`It looks like there is an issue with this instance`), 69 }, 70 expected: pushError{ 71 kind: errKindTenant, 72 }, 73 code: 500, 74 }, 75 76 "400 errors are data errors": { 77 input: &prom.HttpError{ 78 StatusCode: 400, 79 Status: "Bad Request", 80 Err: errors.New(`400 Bad Request: couldn't parse labels: 1:248: parse error: unexpected identifier "foo" in label set, expected "," or "}"`), 81 }, 82 expected: pushError{ 83 kind: errKindPayload, 84 }, 85 code: 400, 86 }, 87 88 "400 err-mimir-sample-out-of-order": { 89 input: &prom.HttpError{ 90 StatusCode: 400, 91 Status: "Bad Request", 92 Err: errors.New(`400 Bad Request: failed pushing to ingester: user=275106: the sample has been rejected because another sample with a more recent timestamp has already been ingested and out-of-order samples are not allowed (err-mimir-sample-out-of-order). The affected sample has timestamp`), 93 }, 94 expected: pushError{ 95 kind: errKindPayload, 96 }, 97 code: 400, 98 }, 99 100 "400 err-mimir-max-series-per-user": { 101 input: &prom.HttpError{ 102 StatusCode: 400, 103 Status: "Bad Request", 104 Err: errors.New(`400 Bad Request: failed pushing to ingester: user=1234: per-user series limit of 15000 exceeded (err-mimir-max-series-per-user). To adjust the related per-tenant limit, configure -ingester.max-global-series-per-user, or contact your service administrator.`), 105 }, 106 expected: pushError{ 107 kind: errKindFatal, 108 }, 109 code: 400, 110 }, 111 112 "429 generic": { 113 input: &prom.HttpError{ 114 StatusCode: 429, 115 Status: "Too Many Requests", 116 Err: errors.New(`the request has been rejected because the tenant exceeded the request rate limit, set to 75 requests/s across all distributors with a maximum allowed burst of 750 (err-mimir-tenant-max-request-rate)`), 117 }, 118 expected: pushError{ 119 kind: errKindWait, 120 }, 121 code: 429, 122 }, 123 124 "429 loki ingest denied": { 125 input: &prom.HttpError{ 126 StatusCode: 429, 127 Status: "Too Many Requests", 128 Err: errors.New(`Ingestion rate limit exceeded for user 1234 (limit: 0 bytes/sec) while attempting to ingest '7' lines totaling '1874' bytes, reduce log volume or contact your Loki administrator to see if the limit can be increased`), 129 }, 130 expected: pushError{ 131 kind: errKindFatal, 132 }, 133 code: 429, 134 }, 135 136 "429 loki active streams": { 137 input: &prom.HttpError{ 138 StatusCode: 429, 139 Status: "Too Many Requests", 140 Err: errors.New(`Maximum active stream limit exceeded, reduce the number of active streams (reduce labels or reduce label values), or contact your Loki administrator to see if the limit can be increased, user: '1234'`), 141 }, 142 expected: pushError{ 143 kind: errKindLimit, 144 }, 145 code: 429, 146 }, 147 148 "404 Not Found": { 149 input: &prom.HttpError{ 150 StatusCode: 404, 151 Status: "Not Found", 152 Err: errors.New("file not found"), 153 }, 154 expected: pushError{ 155 kind: errKindFatal, 156 }, 157 code: 404, 158 }, 159 160 "401 bad token": { 161 input: &prom.HttpError{ 162 StatusCode: 401, 163 Status: "Unauthorized", 164 Err: errors.New(`{"status":"error","error":"authentication error: invalid token"}`), 165 }, 166 expected: pushError{ 167 kind: errKindTenant, 168 }, 169 code: 401, 170 }, 171 172 "403 Forbidden": { 173 input: &prom.HttpError{ 174 StatusCode: 403, 175 Status: "Forbidden", 176 Err: errors.New(`Forbidden`), 177 }, 178 expected: pushError{ 179 kind: errKindFatal, 180 }, 181 code: 403, 182 }, 183 184 "300 response": { 185 input: &prom.HttpError{ 186 StatusCode: 300, 187 Status: "Multiple Choices", 188 Err: errors.New("multiple choices"), 189 }, 190 expected: pushError{ 191 kind: errKindFatal, 192 }, 193 code: 300, 194 }, 195 } { 196 t.Run(title, func(t *testing.T) { 197 code, err := parsePublishError(tc.input) 198 199 var ( 200 expectedErr = tc.expected 201 pErr pushError 202 ) 203 if errors.As(expectedErr, &pErr) { 204 pErr.inner = tc.input 205 expectedErr = pErr 206 } 207 208 require.Equal(t, expectedErr, err) 209 require.Equal(t, tc.code, code) 210 }) 211 } 212 }