| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package squidlog |
| 4 | |
| 5 | import ( |
| 6 | "errors" |
| 7 | "fmt" |
| 8 | "strconv" |
| 9 | "testing" |
| 10 | |
| 11 | "github.com/stretchr/testify/assert" |
| 12 | "github.com/stretchr/testify/require" |
| 13 | ) |
| 14 | |
| 15 | const emptyStr = "" |
| 16 | |
| 17 | func TestLogLine_Assign(t *testing.T) { |
| 18 | type subTest struct { |
| 19 | input string |
| 20 | wantLine logLine |
| 21 | wantErr error |
| 22 | } |
| 23 | type test struct { |
| 24 | name string |
| 25 | field string |
| 26 | cases []subTest |
| 27 | } |
| 28 | tests := []test{ |
| 29 | { |
| 30 | name: "Response Time", |
| 31 | field: fieldRespTime, |
| 32 | cases: []subTest{ |
| 33 | {input: "0", wantLine: logLine{respTime: 0}}, |
| 34 | {input: "1000", wantLine: logLine{respTime: 1000}}, |
| 35 | {input: emptyStr, wantLine: emptyLogLine}, |
| 36 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadRespTime}, |
| 37 | {input: "-1", wantLine: emptyLogLine, wantErr: errBadRespTime}, |
| 38 | {input: "0.000", wantLine: emptyLogLine, wantErr: errBadRespTime}, |
| 39 | }, |
| 40 | }, |
| 41 | { |
| 42 | name: "Client Address", |
| 43 | field: fieldClientAddr, |
| 44 | cases: []subTest{ |
| 45 | {input: "127.0.0.1", wantLine: logLine{clientAddr: "127.0.0.1"}}, |
| 46 | {input: "::1", wantLine: logLine{clientAddr: "::1"}}, |
| 47 | {input: "kadr20.m1.netdata.lan", wantLine: logLine{clientAddr: "kadr20.m1.netdata.lan"}}, |
| 48 | {input: "±!@#$%^&*()", wantLine: logLine{clientAddr: "±!@#$%^&*()"}}, |
| 49 | {input: emptyStr, wantLine: emptyLogLine}, |
| 50 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadClientAddr}, |
| 51 | }, |
| 52 | }, |
| 53 | { |
| 54 | name: "Cache Code", |
| 55 | field: fieldCacheCode, |
| 56 | cases: []subTest{ |
| 57 | {input: "TCP_MISS", wantLine: logLine{cacheCode: "TCP_MISS"}}, |
| 58 | {input: "TCP_DENIED", wantLine: logLine{cacheCode: "TCP_DENIED"}}, |
| 59 | {input: "TCP_CLIENT_REFRESH_MISS", wantLine: logLine{cacheCode: "TCP_CLIENT_REFRESH_MISS"}}, |
| 60 | {input: "UDP_MISS_NOFETCH", wantLine: logLine{cacheCode: "UDP_MISS_NOFETCH"}}, |
| 61 | {input: "UDP_INVALID", wantLine: logLine{cacheCode: "UDP_INVALID"}}, |
| 62 | {input: "NONE", wantLine: logLine{cacheCode: "NONE"}}, |
| 63 | {input: "NONE_NONE", wantLine: logLine{cacheCode: "NONE_NONE"}}, |
| 64 | {input: emptyStr, wantLine: emptyLogLine}, |
| 65 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadCacheCode}, |
| 66 | {input: "TCP", wantLine: emptyLogLine, wantErr: errBadCacheCode}, |
| 67 | {input: "UDP_", wantLine: emptyLogLine, wantErr: errBadCacheCode}, |
| 68 | {input: "NONE_MISS", wantLine: emptyLogLine, wantErr: errBadCacheCode}, |
| 69 | }, |
| 70 | }, |
| 71 | { |
| 72 | name: "HTTP Code", |
| 73 | field: fieldHTTPCode, |
| 74 | cases: []subTest{ |
| 75 | {input: "000", wantLine: logLine{httpCode: 0}}, |
| 76 | {input: "100", wantLine: logLine{httpCode: 100}}, |
| 77 | {input: "200", wantLine: logLine{httpCode: 200}}, |
| 78 | {input: "300", wantLine: logLine{httpCode: 300}}, |
| 79 | {input: "400", wantLine: logLine{httpCode: 400}}, |
| 80 | {input: "500", wantLine: logLine{httpCode: 500}}, |
| 81 | {input: "603", wantLine: logLine{httpCode: 603}}, |
| 82 | {input: emptyStr, wantLine: emptyLogLine}, |
| 83 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadHTTPCode}, |
| 84 | {input: "1", wantLine: emptyLogLine, wantErr: errBadHTTPCode}, |
| 85 | {input: "604", wantLine: emptyLogLine, wantErr: errBadHTTPCode}, |
| 86 | {input: "1000", wantLine: emptyLogLine, wantErr: errBadHTTPCode}, |
| 87 | {input: "TCP_MISS", wantLine: emptyLogLine, wantErr: errBadHTTPCode}, |
| 88 | }, |
| 89 | }, |
| 90 | { |
| 91 | name: "Response Size", |
| 92 | field: fieldRespSize, |
| 93 | cases: []subTest{ |
| 94 | {input: "0", wantLine: logLine{respSize: 0}}, |
| 95 | {input: "1000", wantLine: logLine{respSize: 1000}}, |
| 96 | {input: emptyStr, wantLine: emptyLogLine}, |
| 97 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadRespSize}, |
| 98 | {input: "-1", wantLine: emptyLogLine, wantErr: errBadRespSize}, |
| 99 | {input: "0.000", wantLine: emptyLogLine, wantErr: errBadRespSize}, |
| 100 | }, |
| 101 | }, |
| 102 | { |
| 103 | name: "Request Method", |
| 104 | field: fieldReqMethod, |
| 105 | cases: []subTest{ |
| 106 | {input: "GET", wantLine: logLine{reqMethod: "GET"}}, |
| 107 | {input: "HEAD", wantLine: logLine{reqMethod: "HEAD"}}, |
| 108 | {input: "POST", wantLine: logLine{reqMethod: "POST"}}, |
| 109 | {input: "PUT", wantLine: logLine{reqMethod: "PUT"}}, |
| 110 | {input: "PATCH", wantLine: logLine{reqMethod: "PATCH"}}, |
| 111 | {input: "DELETE", wantLine: logLine{reqMethod: "DELETE"}}, |
| 112 | {input: "CONNECT", wantLine: logLine{reqMethod: "CONNECT"}}, |
| 113 | {input: "OPTIONS", wantLine: logLine{reqMethod: "OPTIONS"}}, |
| 114 | {input: "TRACE", wantLine: logLine{reqMethod: "TRACE"}}, |
| 115 | {input: "ICP_QUERY", wantLine: logLine{reqMethod: "ICP_QUERY"}}, |
| 116 | {input: "PURGE", wantLine: logLine{reqMethod: "PURGE"}}, |
| 117 | {input: "PROPFIND", wantLine: logLine{reqMethod: "PROPFIND"}}, |
| 118 | {input: "PROPATCH", wantLine: logLine{reqMethod: "PROPATCH"}}, |
| 119 | {input: "MKCOL", wantLine: logLine{reqMethod: "MKCOL"}}, |
| 120 | {input: "COPY", wantLine: logLine{reqMethod: "COPY"}}, |
| 121 | {input: "MOVE", wantLine: logLine{reqMethod: "MOVE"}}, |
| 122 | {input: "LOCK", wantLine: logLine{reqMethod: "LOCK"}}, |
| 123 | {input: "UNLOCK", wantLine: logLine{reqMethod: "UNLOCK"}}, |
| 124 | {input: "NONE", wantLine: logLine{reqMethod: "NONE"}}, |
| 125 | {input: emptyStr, wantLine: emptyLogLine}, |
| 126 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadReqMethod}, |
| 127 | {input: "get", wantLine: emptyLogLine, wantErr: errBadReqMethod}, |
| 128 | {input: "0.000", wantLine: emptyLogLine, wantErr: errBadReqMethod}, |
| 129 | {input: "TCP_MISS", wantLine: emptyLogLine, wantErr: errBadReqMethod}, |
| 130 | }, |
| 131 | }, |
| 132 | { |
| 133 | name: "Hier Code", |
| 134 | field: fieldHierCode, |
| 135 | cases: []subTest{ |
| 136 | {input: "HIER_NONE", wantLine: logLine{hierCode: "HIER_NONE"}}, |
| 137 | {input: "HIER_SIBLING_HIT", wantLine: logLine{hierCode: "HIER_SIBLING_HIT"}}, |
| 138 | {input: "HIER_NO_CACHE_DIGEST_DIRECT", wantLine: logLine{hierCode: "HIER_NO_CACHE_DIGEST_DIRECT"}}, |
| 139 | {input: emptyStr, wantLine: emptyLogLine}, |
| 140 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 141 | {input: "0.000", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 142 | {input: "TCP_MISS", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 143 | {input: "HIER", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 144 | {input: "HIER_", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 145 | {input: "NONE", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 146 | {input: "SIBLING_HIT", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 147 | {input: "NO_CACHE_DIGEST_DIRECT", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 148 | }, |
| 149 | }, |
| 150 | { |
| 151 | name: "Server Address", |
| 152 | field: fieldServerAddr, |
| 153 | cases: []subTest{ |
| 154 | {input: "127.0.0.1", wantLine: logLine{serverAddr: "127.0.0.1"}}, |
| 155 | {input: "::1", wantLine: logLine{serverAddr: "::1"}}, |
| 156 | {input: "kadr20.m1.netdata.lan", wantLine: logLine{serverAddr: "kadr20.m1.netdata.lan"}}, |
| 157 | {input: "±!@#$%^&*()", wantLine: logLine{serverAddr: "±!@#$%^&*()"}}, |
| 158 | {input: emptyStr, wantLine: emptyLogLine}, |
| 159 | {input: hyphen, wantLine: emptyLogLine}, |
| 160 | }, |
| 161 | }, |
| 162 | { |
| 163 | name: "Mime Type", |
| 164 | field: fieldMimeType, |
| 165 | cases: []subTest{ |
| 166 | {input: "application/zstd", wantLine: logLine{mimeType: "application"}}, |
| 167 | {input: "audio/3gpp2", wantLine: logLine{mimeType: "audio"}}, |
| 168 | {input: "font/otf", wantLine: logLine{mimeType: "font"}}, |
| 169 | {input: "image/tiff", wantLine: logLine{mimeType: "image"}}, |
| 170 | {input: "message/global", wantLine: logLine{mimeType: "message"}}, |
| 171 | {input: "model/example", wantLine: logLine{mimeType: "model"}}, |
| 172 | {input: "multipart/encrypted", wantLine: logLine{mimeType: "multipart"}}, |
| 173 | {input: "text/html", wantLine: logLine{mimeType: "text"}}, |
| 174 | {input: "video/3gpp", wantLine: logLine{mimeType: "video"}}, |
| 175 | {input: emptyStr, wantLine: emptyLogLine}, |
| 176 | {input: hyphen, wantLine: emptyLogLine}, |
| 177 | {input: "example/example", wantLine: emptyLogLine}, |
| 178 | {input: "unknown/example", wantLine: emptyLogLine}, |
| 179 | {input: "audio", wantLine: emptyLogLine, wantErr: errBadMimeType}, |
| 180 | {input: "/", wantLine: emptyLogLine, wantErr: errBadMimeType}, |
| 181 | }, |
| 182 | }, |
| 183 | { |
| 184 | name: "Result Code", |
| 185 | field: fieldResultCode, |
| 186 | cases: []subTest{ |
| 187 | {input: "TCP_MISS/000", wantLine: logLine{cacheCode: "TCP_MISS", httpCode: 0}}, |
| 188 | {input: "TCP_DENIED/603", wantLine: logLine{cacheCode: "TCP_DENIED", httpCode: 603}}, |
| 189 | {input: emptyStr, wantLine: emptyLogLine}, |
| 190 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadResultCode}, |
| 191 | {input: "TCP_MISS:000", wantLine: emptyLogLine, wantErr: errBadResultCode}, |
| 192 | {input: "TCP_MISS 000", wantLine: emptyLogLine, wantErr: errBadResultCode}, |
| 193 | {input: "/", wantLine: emptyLogLine, wantErr: errBadResultCode}, |
| 194 | {input: "tcp/000", wantLine: emptyLogLine, wantErr: errBadCacheCode}, |
| 195 | {input: "TCP_MISS/", wantLine: logLine{cacheCode: "TCP_MISS", httpCode: emptyNumber}, wantErr: errBadHTTPCode}, |
| 196 | }, |
| 197 | }, |
| 198 | { |
| 199 | name: "Hierarchy", |
| 200 | field: fieldHierarchy, |
| 201 | cases: []subTest{ |
| 202 | {input: "HIER_NONE/-", wantLine: logLine{hierCode: "HIER_NONE", serverAddr: emptyString}}, |
| 203 | {input: "HIER_SIBLING_HIT/127.0.0.1", wantLine: logLine{hierCode: "HIER_SIBLING_HIT", serverAddr: "127.0.0.1"}}, |
| 204 | {input: emptyStr, wantLine: emptyLogLine}, |
| 205 | {input: hyphen, wantLine: emptyLogLine, wantErr: errBadHierarchy}, |
| 206 | {input: "HIER_NONE:-", wantLine: emptyLogLine, wantErr: errBadHierarchy}, |
| 207 | {input: "HIER_SIBLING_HIT 127.0.0.1", wantLine: emptyLogLine, wantErr: errBadHierarchy}, |
| 208 | {input: "/", wantLine: emptyLogLine, wantErr: errBadHierarchy}, |
| 209 | {input: "HIER/-", wantLine: emptyLogLine, wantErr: errBadHierCode}, |
| 210 | {input: "HIER_NONE/", wantLine: logLine{hierCode: "HIER_NONE", serverAddr: emptyStr}}, |
| 211 | }, |
| 212 | }, |
| 213 | } |
| 214 | |
| 215 | for _, tt := range tests { |
| 216 | for i, tc := range tt.cases { |
| 217 | name := fmt.Sprintf("[%s:%d]field='%s'|input='%s'", tt.name, i+1, tt.field, tc.input) |
| 218 | t.Run(name, func(t *testing.T) { |
| 219 | |
| 220 | line := newEmptyLogLine() |
| 221 | err := line.Assign(tt.field, tc.input) |
| 222 | |
| 223 | if tc.wantErr != nil { |
| 224 | require.Error(t, err) |
| 225 | assert.Truef(t, errors.Is(err, tc.wantErr), "expected '%v' error, got '%v'", tc.wantErr, err) |
| 226 | } else { |
| 227 | require.NoError(t, err) |
| 228 | } |
| 229 | |
| 230 | expected := prepareAssignLogLine(t, tt.field, tc.wantLine) |
| 231 | assert.Equal(t, expected, *line) |
| 232 | }) |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | func TestLogLine_verify(t *testing.T) { |
| 238 | type subTest struct { |
| 239 | input string |
| 240 | wantErr error |
| 241 | } |
| 242 | type test = struct { |
| 243 | name string |
| 244 | field string |
| 245 | cases []subTest |
| 246 | } |
| 247 | tests := []test{ |
| 248 | { |
| 249 | name: "Response Time", |
| 250 | field: fieldRespTime, |
| 251 | cases: []subTest{ |
| 252 | {input: "0"}, |
| 253 | {input: "1000"}, |
| 254 | {input: "-1", wantErr: errBadRespTime}, |
| 255 | }, |
| 256 | }, |
| 257 | { |
| 258 | name: "Client Address", |
| 259 | field: fieldClientAddr, |
| 260 | cases: []subTest{ |
| 261 | {input: "127.0.0.1"}, |
| 262 | {input: "::1"}, |
| 263 | {input: "kadr20.m1.netdata.lan"}, |
| 264 | {input: emptyStr}, |
| 265 | {input: "±!@#$%^&*()", wantErr: errBadClientAddr}, |
| 266 | }, |
| 267 | }, |
| 268 | { |
| 269 | name: "Cache Code", |
| 270 | field: fieldCacheCode, |
| 271 | cases: []subTest{ |
| 272 | {input: "TCP_MISS"}, |
| 273 | {input: "TCP_DENIED"}, |
| 274 | {input: "TCP_CLIENT_REFRESH_MISS"}, |
| 275 | {input: "UDP_MISS_NOFETCH"}, |
| 276 | {input: "UDP_INVALID"}, |
| 277 | {input: "NONE"}, |
| 278 | {input: "NONE_NONE"}, |
| 279 | {input: emptyStr}, |
| 280 | {input: "TCP", wantErr: errBadCacheCode}, |
| 281 | {input: "UDP", wantErr: errBadCacheCode}, |
| 282 | {input: "NONE_MISS", wantErr: errBadCacheCode}, |
| 283 | }, |
| 284 | }, |
| 285 | { |
| 286 | name: "HTTP Code", |
| 287 | field: fieldHTTPCode, |
| 288 | cases: []subTest{ |
| 289 | {input: "000"}, |
| 290 | {input: "100"}, |
| 291 | {input: "200"}, |
| 292 | {input: "300"}, |
| 293 | {input: "400"}, |
| 294 | {input: "500"}, |
| 295 | {input: "603"}, |
| 296 | {input: "1", wantErr: errBadHTTPCode}, |
| 297 | {input: "604", wantErr: errBadHTTPCode}, |
| 298 | }, |
| 299 | }, |
| 300 | { |
| 301 | name: "Response Size", |
| 302 | field: fieldRespSize, |
| 303 | cases: []subTest{ |
| 304 | {input: "0"}, |
| 305 | {input: "1000"}, |
| 306 | {input: "-1", wantErr: errBadRespSize}, |
| 307 | }, |
| 308 | }, |
| 309 | { |
| 310 | name: "Request Method", |
| 311 | field: fieldReqMethod, |
| 312 | cases: []subTest{ |
| 313 | {input: "GET"}, |
| 314 | {input: "HEAD"}, |
| 315 | {input: "POST"}, |
| 316 | {input: "PUT"}, |
| 317 | {input: "PATCH"}, |
| 318 | {input: "DELETE"}, |
| 319 | {input: "CONNECT"}, |
| 320 | {input: "OPTIONS"}, |
| 321 | {input: "TRACE"}, |
| 322 | {input: "ICP_QUERY"}, |
| 323 | {input: "PURGE"}, |
| 324 | {input: "PROPFIND"}, |
| 325 | {input: "PROPATCH"}, |
| 326 | {input: "MKCOL"}, |
| 327 | {input: "COPY"}, |
| 328 | {input: "MOVE"}, |
| 329 | {input: "LOCK"}, |
| 330 | {input: "UNLOCK"}, |
| 331 | {input: "NONE"}, |
| 332 | {input: emptyStr}, |
| 333 | {input: "get", wantErr: errBadReqMethod}, |
| 334 | {input: "TCP_MISS", wantErr: errBadReqMethod}, |
| 335 | }, |
| 336 | }, |
| 337 | { |
| 338 | name: "Hier Code", |
| 339 | field: fieldHierCode, |
| 340 | cases: []subTest{ |
| 341 | {input: "HIER_NONE"}, |
| 342 | {input: "HIER_SIBLING_HIT"}, |
| 343 | {input: "HIER_NO_CACHE_DIGEST_DIRECT"}, |
| 344 | {input: emptyStr}, |
| 345 | {input: "0.000", wantErr: errBadHierCode}, |
| 346 | {input: "TCP_MISS", wantErr: errBadHierCode}, |
| 347 | {input: "HIER", wantErr: errBadHierCode}, |
| 348 | {input: "HIER_", wantErr: errBadHierCode}, |
| 349 | {input: "NONE", wantErr: errBadHierCode}, |
| 350 | {input: "SIBLING_HIT", wantErr: errBadHierCode}, |
| 351 | {input: "NO_CACHE_DIGEST_DIRECT", wantErr: errBadHierCode}, |
| 352 | }, |
| 353 | }, |
| 354 | { |
| 355 | name: "Server Address", |
| 356 | field: fieldServerAddr, |
| 357 | cases: []subTest{ |
| 358 | {input: "127.0.0.1"}, |
| 359 | {input: "::1"}, |
| 360 | {input: "kadr20.m1.netdata.lan"}, |
| 361 | {input: emptyStr}, |
| 362 | {input: "±!@#$%^&*()", wantErr: errBadServerAddr}, |
| 363 | }, |
| 364 | }, |
| 365 | { |
| 366 | name: "Mime Type", |
| 367 | field: fieldMimeType, |
| 368 | cases: []subTest{ |
| 369 | {input: "application"}, |
| 370 | {input: "audio"}, |
| 371 | {input: "font"}, |
| 372 | {input: "image"}, |
| 373 | {input: "message"}, |
| 374 | {input: "model"}, |
| 375 | {input: "multipart"}, |
| 376 | {input: "text"}, |
| 377 | {input: "video"}, |
| 378 | {input: emptyStr}, |
| 379 | {input: "example/example", wantErr: errBadMimeType}, |
| 380 | {input: "unknown", wantErr: errBadMimeType}, |
| 381 | {input: "/", wantErr: errBadMimeType}, |
| 382 | }, |
| 383 | }, |
| 384 | } |
| 385 | |
| 386 | for _, tt := range tests { |
| 387 | for i, tc := range tt.cases { |
| 388 | name := fmt.Sprintf("[%s:%d]field='%s'|input='%s'", tt.name, i+1, tt.field, tc.input) |
| 389 | t.Run(name, func(t *testing.T) { |
| 390 | line := prepareVerifyLogLine(t, tt.field, tc.input) |
| 391 | |
| 392 | err := line.verify() |
| 393 | |
| 394 | if tc.wantErr != nil { |
| 395 | require.Error(t, err) |
| 396 | assert.Truef(t, errors.Is(err, tc.wantErr), "expected '%v' error, got '%v'", tc.wantErr, err) |
| 397 | } else { |
| 398 | require.NoError(t, err) |
| 399 | } |
| 400 | }) |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | func prepareAssignLogLine(t *testing.T, field string, template logLine) logLine { |
| 406 | t.Helper() |
| 407 | if template.empty() { |
| 408 | return template |
| 409 | } |
| 410 | |
| 411 | var line logLine |
| 412 | line.reset() |
| 413 | |
| 414 | switch field { |
| 415 | default: |
| 416 | t.Errorf("prepareAssignLogLine unknown field: '%s'", field) |
| 417 | case fieldRespTime: |
| 418 | line.respTime = template.respTime |
| 419 | case fieldClientAddr: |
| 420 | line.clientAddr = template.clientAddr |
| 421 | case fieldCacheCode: |
| 422 | line.cacheCode = template.cacheCode |
| 423 | case fieldHTTPCode: |
| 424 | line.httpCode = template.httpCode |
| 425 | case fieldRespSize: |
| 426 | line.respSize = template.respSize |
| 427 | case fieldReqMethod: |
| 428 | line.reqMethod = template.reqMethod |
| 429 | case fieldHierCode: |
| 430 | line.hierCode = template.hierCode |
| 431 | case fieldMimeType: |
| 432 | line.mimeType = template.mimeType |
| 433 | case fieldServerAddr: |
| 434 | line.serverAddr = template.serverAddr |
| 435 | case fieldResultCode: |
| 436 | line.cacheCode = template.cacheCode |
| 437 | line.httpCode = template.httpCode |
| 438 | case fieldHierarchy: |
| 439 | line.hierCode = template.hierCode |
| 440 | line.serverAddr = template.serverAddr |
| 441 | } |
| 442 | return line |
| 443 | } |
| 444 | |
| 445 | func prepareVerifyLogLine(t *testing.T, field string, value string) logLine { |
| 446 | t.Helper() |
| 447 | var line logLine |
| 448 | line.reset() |
| 449 | |
| 450 | switch field { |
| 451 | default: |
| 452 | t.Errorf("prepareVerifyLogLine unknown field: '%s'", field) |
| 453 | case fieldRespTime: |
| 454 | v, err := strconv.Atoi(value) |
| 455 | require.NoError(t, err) |
| 456 | line.respTime = v |
| 457 | case fieldClientAddr: |
| 458 | line.clientAddr = value |
| 459 | case fieldCacheCode: |
| 460 | line.cacheCode = value |
| 461 | case fieldHTTPCode: |
| 462 | v, err := strconv.Atoi(value) |
| 463 | require.NoError(t, err) |
| 464 | line.httpCode = v |
| 465 | case fieldRespSize: |
| 466 | v, err := strconv.Atoi(value) |
| 467 | require.NoError(t, err) |
| 468 | line.respSize = v |
| 469 | case fieldReqMethod: |
| 470 | line.reqMethod = value |
| 471 | case fieldHierCode: |
| 472 | line.hierCode = value |
| 473 | case fieldMimeType: |
| 474 | line.mimeType = value |
| 475 | case fieldServerAddr: |
| 476 | line.serverAddr = value |
| 477 | } |
| 478 | return line |
| 479 | } |