github.com/google/martian/v3@v3.3.3/har/har_test.go (about) 1 // Copyright 2015 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package har 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "mime/multipart" 21 "net/http" 22 "reflect" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/google/martian/v3" 28 "github.com/google/martian/v3/proxyutil" 29 ) 30 31 func TestModifyRequest(t *testing.T) { 32 req, err := http.NewRequest("GET", "http://example.com/path?query=true", nil) 33 if err != nil { 34 t.Fatalf("http.NewRequest(): got %v, want no error", err) 35 } 36 req.Header.Add("Request-Header", "first") 37 req.Header.Add("Request-Header", "second") 38 39 cookie := &http.Cookie{ 40 Name: "request", 41 Value: "cookie", 42 } 43 req.AddCookie(cookie) 44 45 _, remove, err := martian.TestContext(req, nil, nil) 46 if err != nil { 47 t.Fatalf("martian.TestContext(): got %v, want no error", err) 48 } 49 defer remove() 50 51 logger := NewLogger() 52 if err := logger.ModifyRequest(req); err != nil { 53 t.Fatalf("ModifyRequest(): got %v, want no error", err) 54 } 55 56 log := logger.Export().Log 57 if got, want := log.Version, "1.2"; got != want { 58 t.Errorf("log.Version: got %q, want %q", got, want) 59 } 60 61 if got, want := len(log.Entries), 1; got != want { 62 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 63 } 64 65 entry := log.Entries[0] 66 if got, want := time.Since(entry.StartedDateTime), time.Second; got > want { 67 t.Errorf("entry.StartedDateTime: got %s, want less than %s", got, want) 68 } 69 70 hreq := entry.Request 71 if got, want := hreq.Method, "GET"; got != want { 72 t.Errorf("hreq.Method: got %q, want %q", got, want) 73 } 74 75 if got, want := hreq.URL, "http://example.com/path?query=true"; got != want { 76 t.Errorf("hreq.URL: got %q, want %q", got, want) 77 } 78 79 if got, want := hreq.HTTPVersion, "HTTP/1.1"; got != want { 80 t.Errorf("hreq.HTTPVersion: got %q, want %q", got, want) 81 } 82 83 if got, want := hreq.BodySize, int64(0); got != want { 84 t.Errorf("hreq.BodySize: got %d, want %d", got, want) 85 } 86 87 if got, want := hreq.HeadersSize, int64(-1); got != want { 88 t.Errorf("hreq.HeadersSize: got %d, want %d", got, want) 89 } 90 91 if got, want := len(hreq.QueryString), 1; got != want { 92 t.Fatalf("len(hreq.QueryString): got %d, want %q", got, want) 93 } 94 95 qs := hreq.QueryString[0] 96 if got, want := qs.Name, "query"; got != want { 97 t.Errorf("qs.Name: got %q, want %q", got, want) 98 } 99 if got, want := qs.Value, "true"; got != want { 100 t.Errorf("qs.Value: got %q, want %q", got, want) 101 } 102 103 wantHeaders := http.Header{ 104 "Request-Header": {"first", "second"}, 105 "Cookie": {cookie.String()}, 106 "Host": {"example.com"}, 107 } 108 if got := headersToHTTP(hreq.Headers); !reflect.DeepEqual(got, wantHeaders) { 109 t.Errorf("headers:\ngot:\n%+v\nwant:\n%+v", got, wantHeaders) 110 } 111 112 if got, want := len(hreq.Cookies), 1; got != want { 113 t.Fatalf("len(hreq.Cookies): got %d, want %d", got, want) 114 } 115 116 hcookie := hreq.Cookies[0] 117 if got, want := hcookie.Name, "request"; got != want { 118 t.Errorf("hcookie.Name: got %q, want %q", got, want) 119 } 120 if got, want := hcookie.Value, "cookie"; got != want { 121 t.Errorf("hcookie.Value: got %q, want %q", got, want) 122 } 123 } 124 125 func headersToHTTP(hs []Header) http.Header { 126 hh := http.Header{} 127 for _, h := range hs { 128 hh[h.Name] = append(hh[h.Name], h.Value) 129 } 130 return hh 131 } 132 133 func TestModifyResponse(t *testing.T) { 134 req, err := http.NewRequest("GET", "http://example.com", nil) 135 if err != nil { 136 t.Fatalf("NewRequest(): got %v, want no error", err) 137 } 138 139 _, remove, err := martian.TestContext(req, nil, nil) 140 if err != nil { 141 t.Fatalf("martian.TestContext(): got %v, want no error", err) 142 } 143 defer remove() 144 145 res := proxyutil.NewResponse(301, strings.NewReader("response body"), req) 146 res.ContentLength = 13 147 res.Header.Add("Response-Header", "first") 148 res.Header.Add("Response-Header", "second") 149 res.Header.Set("Location", "google.com") 150 151 expires := time.Now() 152 cookie := &http.Cookie{ 153 Name: "response", 154 Value: "cookie", 155 Path: "/", 156 Domain: "example.com", 157 Expires: expires, 158 Secure: true, 159 HttpOnly: true, 160 } 161 res.Header.Set("Set-Cookie", cookie.String()) 162 163 logger := NewLogger() 164 165 if err := logger.ModifyRequest(req); err != nil { 166 t.Fatalf("ModifyRequest(): got %v, want no error", err) 167 } 168 169 if err := logger.ModifyResponse(res); err != nil { 170 t.Fatalf("ModifyResponse(): got %v, want no error", err) 171 } 172 173 log := logger.Export().Log 174 if got, want := len(log.Entries), 1; got != want { 175 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 176 } 177 178 hres := log.Entries[0].Response 179 if got, want := hres.Status, 301; got != want { 180 t.Errorf("hres.Status: got %d, want %d", got, want) 181 } 182 183 if got, want := hres.StatusText, "Moved Permanently"; got != want { 184 t.Errorf("hres.StatusText: got %q, want %q", got, want) 185 } 186 187 if got, want := hres.HTTPVersion, "HTTP/1.1"; got != want { 188 t.Errorf("hres.HTTPVersion: got %q, want %q", got, want) 189 } 190 191 if got, want := hres.Content.Text, []byte("response body"); !bytes.Equal(got, want) { 192 t.Errorf("hres.Content.Text: got %q, want %q", got, want) 193 } 194 195 wantHeaders := http.Header{ 196 "Response-Header": {"first", "second"}, 197 "Set-Cookie": {cookie.String()}, 198 "Location": {"google.com"}, 199 "Content-Length": {"13"}, 200 } 201 if got := headersToHTTP(hres.Headers); !reflect.DeepEqual(got, wantHeaders) { 202 t.Errorf("headers:\ngot:\n%+v\nwant:\n%+v", got, wantHeaders) 203 } 204 205 if got, want := len(hres.Cookies), 1; got != want { 206 t.Fatalf("len(hres.Cookies): got %d, want %d", got, want) 207 } 208 209 hcookie := hres.Cookies[0] 210 if got, want := hcookie.Name, "response"; got != want { 211 t.Errorf("hcookie.Name: got %q, want %q", got, want) 212 } 213 if got, want := hcookie.Value, "cookie"; got != want { 214 t.Errorf("hcookie.Value: got %q, want %q", got, want) 215 } 216 if got, want := hcookie.Path, "/"; got != want { 217 t.Errorf("hcookie.Path: got %q, want %q", got, want) 218 } 219 if got, want := hcookie.Domain, "example.com"; got != want { 220 t.Errorf("hcookie.Domain: got %q, want %q", got, want) 221 } 222 if got, want := hcookie.Expires, expires; got.Equal(want) { 223 t.Errorf("hcookie.Expires: got %s, want %s", got, want) 224 } 225 if !hcookie.HTTPOnly { 226 t.Error("hcookie.HTTPOnly: got false, want true") 227 } 228 if !hcookie.Secure { 229 t.Error("hcookie.Secure: got false, want true") 230 } 231 } 232 233 func TestModifyRequestBodyURLEncoded(t *testing.T) { 234 logger := NewLogger() 235 236 body := strings.NewReader("first=true&second=false") 237 req, err := http.NewRequest("POST", "http://example.com", body) 238 if err != nil { 239 t.Fatalf("http.NewRequest(): got %v, want no error", err) 240 } 241 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 242 243 _, remove, err := martian.TestContext(req, nil, nil) 244 if err != nil { 245 t.Fatalf("martian.TestContext(): got %v, want no error", err) 246 } 247 defer remove() 248 249 if err := logger.ModifyRequest(req); err != nil { 250 t.Fatalf("ModifyRequest(): got %v, want no error", err) 251 } 252 253 log := logger.Export().Log 254 if got, want := len(log.Entries), 1; got != want { 255 t.Errorf("len(log.Entries): got %v, want %v", got, want) 256 } 257 258 pd := log.Entries[0].Request.PostData 259 if got, want := pd.MimeType, "application/x-www-form-urlencoded"; got != want { 260 t.Errorf("PostData.MimeType: got %v, want %v", got, want) 261 } 262 263 if got, want := len(pd.Params), 2; got != want { 264 t.Fatalf("len(PostData.Params): got %d, want %d", got, want) 265 } 266 267 for _, p := range pd.Params { 268 var want string 269 switch p.Name { 270 case "first": 271 want = "true" 272 case "second": 273 want = "false" 274 default: 275 t.Errorf("PostData.Params: got %q, want to not be present", p.Name) 276 continue 277 } 278 279 if got := p.Value; got != want { 280 t.Errorf("PostData.Params[%q]: got %q, want %q", p.Name, got, want) 281 } 282 } 283 } 284 285 func TestModifyRequestBodyArbitraryContentType(t *testing.T) { 286 logger := NewLogger() 287 288 body := "arbitrary binary data" 289 req, err := http.NewRequest("POST", "http://www.example.com", strings.NewReader(body)) 290 if err != nil { 291 t.Fatalf("http.NewRequest(): got %v, want no error", err) 292 } 293 294 _, remove, err := martian.TestContext(req, nil, nil) 295 if err != nil { 296 t.Fatalf("martian.TestContext(): got %v, want no error", err) 297 } 298 defer remove() 299 300 if err := logger.ModifyRequest(req); err != nil { 301 t.Fatalf("ModifyRequest(): got %v, want no error", err) 302 } 303 304 log := logger.Export().Log 305 if got, want := len(log.Entries), 1; got != want { 306 t.Errorf("len(log.Entries): got %d, want %d", got, want) 307 } 308 309 pd := log.Entries[0].Request.PostData 310 if got, want := pd.MimeType, ""; got != want { 311 t.Errorf("PostData.MimeType: got %q, want %q", got, want) 312 } 313 if got, want := len(pd.Params), 0; got != want { 314 t.Errorf("len(PostData.Params): got %d, want %d", got, want) 315 } 316 317 if got, want := pd.Text, body; got != want { 318 t.Errorf("PostData.Text: got %q, want %q", got, want) 319 } 320 } 321 322 func TestModifyRequestBodyMultipart(t *testing.T) { 323 logger := NewLogger() 324 325 body := new(bytes.Buffer) 326 mpw := multipart.NewWriter(body) 327 mpw.SetBoundary("boundary") 328 329 if err := mpw.WriteField("key", "value"); err != nil { 330 t.Errorf("mpw.WriteField(): got %v, want no error", err) 331 } 332 333 w, err := mpw.CreateFormFile("file", "test.txt") 334 if _, err = w.Write([]byte("file contents")); err != nil { 335 t.Fatalf("Write(): got %v, want no error", err) 336 } 337 mpw.Close() 338 339 req, err := http.NewRequest("POST", "http://example.com", body) 340 if err != nil { 341 t.Fatalf("http.NewRequest(): got %v, want no error", err) 342 } 343 req.Header.Set("Content-Type", mpw.FormDataContentType()) 344 345 _, remove, err := martian.TestContext(req, nil, nil) 346 if err != nil { 347 t.Fatalf("martian.TestContext(): got %v, want no error", err) 348 } 349 defer remove() 350 351 if err := logger.ModifyRequest(req); err != nil { 352 t.Fatalf("ModifyRequest(): got %v, want no error", err) 353 } 354 355 log := logger.Export().Log 356 if got, want := len(log.Entries), 1; got != want { 357 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 358 } 359 360 pd := log.Entries[0].Request.PostData 361 if got, want := pd.MimeType, "multipart/form-data"; got != want { 362 t.Errorf("PostData.MimeType: got %q, want %q", got, want) 363 } 364 if got, want := len(pd.Params), 2; got != want { 365 t.Errorf("PostData.Params: got %d, want %d", got, want) 366 } 367 368 for _, p := range pd.Params { 369 var want Param 370 371 switch p.Name { 372 case "key": 373 want = Param{ 374 Filename: "", 375 ContentType: "", 376 Value: "value", 377 } 378 case "file": 379 want = Param{ 380 Filename: "test.txt", 381 ContentType: "application/octet-stream", 382 Value: "file contents", 383 } 384 default: 385 t.Errorf("pd.Params: got %q, want not to be present", p.Name) 386 continue 387 } 388 389 if got, want := p.Filename, want.Filename; got != want { 390 t.Errorf("p.Filename: got %q, want %q", got, want) 391 } 392 if got, want := p.ContentType, want.ContentType; got != want { 393 t.Errorf("p.ContentType: got %q, want %q", got, want) 394 } 395 if got, want := p.Value, want.Value; got != want { 396 t.Errorf("p.Value: got %q, want %q", got, want) 397 } 398 } 399 } 400 401 func TestModifyRequestErrorsOnDuplicateRequest(t *testing.T) { 402 logger := NewLogger() 403 404 req, err := http.NewRequest("POST", "http://example.com", nil) 405 if err != nil { 406 t.Fatalf("http.NewRequest(): got %v, want no error", err) 407 } 408 409 _, remove, err := martian.TestContext(req, nil, nil) 410 if err != nil { 411 t.Fatalf("martian.TestContext(): got %v, want no error", err) 412 } 413 defer remove() 414 415 if err := logger.ModifyRequest(req); err != nil { 416 t.Fatalf("ModifyRequest(): got %v, want no error", err) 417 } 418 419 if logger.ModifyRequest(req) == nil { 420 t.Fatalf("ModifyRequest(): was supposed to error") 421 } 422 } 423 424 func TestHARExportsTime(t *testing.T) { 425 logger := NewLogger() 426 427 req, err := http.NewRequest("GET", "http://example.com", nil) 428 if err != nil { 429 t.Fatalf("NewRequest(): got %v, want no error", err) 430 } 431 432 _, remove, err := martian.TestContext(req, nil, nil) 433 if err != nil { 434 t.Fatalf("martian.TestContext(): got %v, want no error", err) 435 } 436 defer remove() 437 438 if err := logger.ModifyRequest(req); err != nil { 439 t.Fatalf("ModifyRequest(): got %v, want no error", err) 440 } 441 442 // Simulate fast network round trip. 443 time.Sleep(10 * time.Millisecond) 444 445 res := proxyutil.NewResponse(200, nil, req) 446 447 if err := logger.ModifyResponse(res); err != nil { 448 t.Fatalf("ModifyResponse(): got %v, want no error", err) 449 } 450 451 log := logger.Export().Log 452 if got, want := len(log.Entries), 1; got != want { 453 t.Fatalf("len(log.Entries): got %v, want %v", got, want) 454 } 455 456 entry := log.Entries[0] 457 min, max := int64(10), int64(100) 458 if got := entry.Time; got < min || got > max { 459 t.Errorf("entry.Time: got %dms, want between %dms and %vms", got, min, max) 460 } 461 } 462 463 func TestReset(t *testing.T) { 464 logger := NewLogger() 465 466 req, err := http.NewRequest("GET", "http://example.com", nil) 467 if err != nil { 468 t.Fatalf("NewRequest(): got %v, want no error", err) 469 } 470 471 _, remove, err := martian.TestContext(req, nil, nil) 472 if err != nil { 473 t.Fatalf("martian.TestContext(): got %v, want no error", err) 474 } 475 defer remove() 476 477 if err := logger.ModifyRequest(req); err != nil { 478 t.Fatalf("ModifyRequest(): got %v, want no error", err) 479 } 480 481 log := logger.Export().Log 482 if got, want := len(log.Entries), 1; got != want { 483 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 484 } 485 486 logger.Reset() 487 488 log = logger.Export().Log 489 if got, want := len(log.Entries), 0; got != want { 490 t.Errorf("len(log.Entries): got %d, want %d", got, want) 491 } 492 } 493 494 func TestExportSortsEntries(t *testing.T) { 495 logger := NewLogger() 496 count := 10 497 498 for i := 0; i < count; i++ { 499 req, err := http.NewRequest("GET", "http://example.com", nil) 500 if err != nil { 501 t.Fatalf("NewRequest(): got %v, want no error", err) 502 } 503 504 _, remove, err := martian.TestContext(req, nil, nil) 505 if err != nil { 506 t.Fatalf("martian.TestContext(): got %v, want no error", err) 507 } 508 defer remove() 509 510 if err := logger.ModifyRequest(req); err != nil { 511 t.Fatalf("ModifyRequest(): got %v, want no error", err) 512 } 513 } 514 515 log := logger.Export().Log 516 517 for i := 0; i < count-1; i++ { 518 first := log.Entries[i] 519 second := log.Entries[i+1] 520 521 if got, want := first.StartedDateTime, second.StartedDateTime; got.After(want) { 522 t.Errorf("entry.StartedDateTime: got %s, want to be before %s", got, want) 523 } 524 } 525 } 526 527 func TestExportIgnoresOrphanedResponse(t *testing.T) { 528 logger := NewLogger() 529 530 req, err := http.NewRequest("GET", "http://example.com", nil) 531 if err != nil { 532 t.Fatalf("http.NewRequest(): got %v, want no error", err) 533 } 534 535 _, remove, err := martian.TestContext(req, nil, nil) 536 if err != nil { 537 t.Fatalf("martian.TestContext(): got %v, want no error", err) 538 } 539 defer remove() 540 541 if err := logger.ModifyRequest(req); err != nil { 542 t.Fatalf("ModifyRequest(): got %v, want no error", err) 543 } 544 545 // Reset before the response comes back. 546 logger.Reset() 547 548 res := proxyutil.NewResponse(200, nil, req) 549 if err := logger.ModifyResponse(res); err != nil { 550 t.Fatalf("ModifyResponse(): got %v, want no error", err) 551 } 552 553 log := logger.Export().Log 554 if got, want := len(log.Entries), 0; got != want { 555 t.Errorf("len(log.Entries): got %d, want %d", got, want) 556 } 557 } 558 559 func TestExportAndResetResetsCompleteRequests(t *testing.T) { 560 logger := NewLogger() 561 562 req, err := http.NewRequest("GET", "http://example.com", nil) 563 if err != nil { 564 t.Fatalf("http.NewRequest(): got %v, want no error", err) 565 } 566 567 _, remove, err := martian.TestContext(req, nil, nil) 568 if err != nil { 569 t.Fatalf("martian.TestContext(): got %v, want no error", err) 570 } 571 defer remove() 572 573 if err := logger.ModifyRequest(req); err != nil { 574 t.Fatalf("ModifyRequest(): got %v, want no error", err) 575 } 576 577 res := proxyutil.NewResponse(200, nil, req) 578 if err := logger.ModifyResponse(res); err != nil { 579 t.Fatalf("ModifyResponse(): got %v, want no error", err) 580 } 581 582 logger.ExportAndReset() 583 584 log := logger.Export().Log 585 if got, want := len(log.Entries), 0; got != want { 586 t.Errorf("len(log.Entries): got %d, want %d", got, want) 587 } 588 } 589 590 func TestExportAndResetLeavesPendingRequests(t *testing.T) { 591 logger := NewLogger() 592 593 req, err := http.NewRequest("GET", "http://example.com", nil) 594 if err != nil { 595 t.Fatalf("http.NewRequest(): got %v, want no error", err) 596 } 597 598 _, remove, err := martian.TestContext(req, nil, nil) 599 if err != nil { 600 t.Fatalf("martian.TestContext(): got %v, want no error", err) 601 } 602 defer remove() 603 604 if err := logger.ModifyRequest(req); err != nil { 605 t.Fatalf("ModifyRequest(): got %v, want no error", err) 606 } 607 608 logger.ExportAndReset() 609 610 log := logger.Export().Log 611 if got, want := len(log.Entries), 1; got != want { 612 t.Errorf("len(log.Entries): got %d, want %d", got, want) 613 } 614 } 615 616 func TestExportAndResetExportsCompleteRequests(t *testing.T) { 617 logger := NewLogger() 618 619 req, err := http.NewRequest("GET", "http://example.com", nil) 620 if err != nil { 621 t.Fatalf("http.NewRequest(): got %v, want no error", err) 622 } 623 624 _, remove, err := martian.TestContext(req, nil, nil) 625 if err != nil { 626 t.Fatalf("martian.TestContext(): got %v, want no error", err) 627 } 628 defer remove() 629 630 if err := logger.ModifyRequest(req); err != nil { 631 t.Fatalf("ModifyRequest(): got %v, want no error", err) 632 } 633 634 res := proxyutil.NewResponse(200, nil, req) 635 if err := logger.ModifyResponse(res); err != nil { 636 t.Fatalf("ModifyResponse(): got %v, want no error", err) 637 } 638 639 log := logger.ExportAndReset().Log 640 if got, want := len(log.Entries), 1; got != want { 641 t.Errorf("len(log.Entries): got %d, want %d", got, want) 642 } 643 } 644 645 func TestExportAndResetExportsCompleteRequestsWithPendingLeft(t *testing.T) { 646 logger := NewLogger() 647 648 req, err := http.NewRequest("GET", "http://example.com", nil) 649 if err != nil { 650 t.Fatalf("http.NewRequest(): got %v, want no error", err) 651 } 652 653 _, remove, err := martian.TestContext(req, nil, nil) 654 if err != nil { 655 t.Fatalf("martian.TestContext(): got %v, want no error", err) 656 } 657 defer remove() 658 659 if err := logger.ModifyRequest(req); err != nil { 660 t.Fatalf("ModifyRequest(): got %v, want no error", err) 661 } 662 663 req, err = http.NewRequest("GET", "http://example.com", nil) 664 if err != nil { 665 t.Fatalf("http.NewRequest(): got %v, want no error", err) 666 } 667 668 _, remove, err = martian.TestContext(req, nil, nil) 669 if err != nil { 670 t.Fatalf("martian.TestContext(): got %v, want no error", err) 671 } 672 defer remove() 673 674 if err := logger.ModifyRequest(req); err != nil { 675 t.Fatalf("ModifyRequest(): got %v, want no error", err) 676 } 677 678 req, err = http.NewRequest("GET", "http://example.com", nil) 679 if err != nil { 680 t.Fatalf("http.NewRequest(): got %v, want no error", err) 681 } 682 683 _, remove, err = martian.TestContext(req, nil, nil) 684 if err != nil { 685 t.Fatalf("martian.TestContext(): got %v, want no error", err) 686 } 687 defer remove() 688 689 if err := logger.ModifyRequest(req); err != nil { 690 t.Fatalf("ModifyRequest(): got %v, want no error", err) 691 } 692 693 res := proxyutil.NewResponse(200, nil, req) 694 if err := logger.ModifyResponse(res); err != nil { 695 t.Fatalf("ModifyResponse(): got %v, want no error", err) 696 } 697 698 log := logger.ExportAndReset().Log 699 if got, want := len(log.Entries), 1; got != want { 700 t.Errorf("len(log.Entries): got %d, want %d", got, want) 701 } 702 703 log = logger.Export().Log 704 if got, want := len(log.Entries), 2; got != want { 705 t.Errorf("len(log.Entries): got %d, want %d", got, want) 706 } 707 } 708 709 func TestSkippingLogging(t *testing.T) { 710 req, err := http.NewRequest("GET", "http://example.com", nil) 711 if err != nil { 712 t.Fatalf("NewRequest(): got %v, want no error", err) 713 } 714 715 ctx, remove, err := martian.TestContext(req, nil, nil) 716 if err != nil { 717 t.Fatalf("martian.TestContext(): got %v, want no error", err) 718 } 719 defer remove() 720 721 ctx.SkipLogging() 722 723 logger := NewLogger() 724 725 if err := logger.ModifyRequest(req); err != nil { 726 t.Fatalf("ModifyRequest(): got %v, want no error", err) 727 } 728 729 res := proxyutil.NewResponse(200, nil, req) 730 if err := logger.ModifyResponse(res); err != nil { 731 t.Fatalf("ModifyResponse(): got %v, want no error", err) 732 } 733 734 log := logger.Export().Log 735 if got, want := len(log.Entries), 0; got != want { 736 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 737 } 738 } 739 740 func TestOptionResponseBodyLogging(t *testing.T) { 741 req, err := http.NewRequest("GET", "http://example.com", nil) 742 if err != nil { 743 t.Fatalf("NewRequest(): got %v, want no error", err) 744 } 745 746 _, remove, err := martian.TestContext(req, nil, nil) 747 if err != nil { 748 t.Fatalf("martian.TestContext(): got %v, want no error", err) 749 } 750 defer remove() 751 752 bdr := strings.NewReader("{\"response\": \"body\"}") 753 res := proxyutil.NewResponse(200, bdr, req) 754 res.ContentLength = int64(bdr.Len()) 755 res.Header.Set("Content-Type", "application/json") 756 757 logger := NewLogger() 758 759 if err := logger.ModifyRequest(req); err != nil { 760 t.Fatalf("ModifyRequest(): got %v, want no error", err) 761 } 762 763 if err := logger.ModifyResponse(res); err != nil { 764 t.Fatalf("ModifyResponse(): got %v, want no error", err) 765 } 766 767 log := logger.Export().Log 768 if got, want := len(log.Entries), 1; got != want { 769 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 770 } 771 772 if got, want := string(log.Entries[0].Response.Content.Text), "{\"response\": \"body\"}"; got != want { 773 t.Fatalf("log.Entries[0].Response.Content.Text: got %s, want %s", got, want) 774 } 775 776 logger = NewLogger() 777 logger.SetOption(BodyLogging(false)) 778 779 if err := logger.ModifyRequest(req); err != nil { 780 t.Fatalf("ModifyRequest(): got %v, want no error", err) 781 } 782 783 if err := logger.ModifyResponse(res); err != nil { 784 t.Fatalf("ModifyResponse(): got %v, want no error", err) 785 } 786 787 log = logger.Export().Log 788 if got, want := len(log.Entries), 1; got != want { 789 t.Fatalf("len(log.Entries): got %d, want %d", got, want) 790 } 791 792 if got, want := string(log.Entries[0].Response.Content.Text), ""; got != want { 793 t.Fatalf("log.Entries[0].Response.Content: got %s, want %s", got, want) 794 } 795 796 logger = NewLogger() 797 logger.SetOption(BodyLoggingForContentTypes("application/json")) 798 799 if err := logger.ModifyRequest(req); err != nil { 800 t.Fatalf("ModifyRequest(): got %v, want no error", err) 801 } 802 803 if err := logger.ModifyResponse(res); err != nil { 804 t.Fatalf("ModifyResponse(): got %v, want no error", err) 805 } 806 807 log = logger.Export().Log 808 if got, want := string(log.Entries[0].Response.Content.Text), "{\"response\": \"body\"}"; got != want { 809 t.Fatalf("log.Entries[0].Response.Content: got %s, want %s", got, want) 810 } 811 812 logger = NewLogger() 813 logger.SetOption(SkipBodyLoggingForContentTypes("application/json")) 814 815 if err := logger.ModifyRequest(req); err != nil { 816 t.Fatalf("ModifyRequest(): got %v, want no error", err) 817 } 818 819 if err := logger.ModifyResponse(res); err != nil { 820 t.Fatalf("ModifyResponse(): got %v, want no error", err) 821 } 822 823 log = logger.Export().Log 824 if got, want := string(log.Entries[0].Response.Content.Text), ""; got != want { 825 t.Fatalf("log.Entries[0].Response.Content: got %v, want %v", got, want) 826 } 827 } 828 829 func TestOptionRequestPostDataLogging(t *testing.T) { 830 logger := NewLogger() 831 logger.SetOption(PostDataLoggingForContentTypes("application/x-www-form-urlencoded")) 832 833 body := strings.NewReader("first=true&second=false") 834 req, err := http.NewRequest("POST", "http://example.com", body) 835 if err != nil { 836 t.Fatalf("http.NewRequest(): got %v, want no error", err) 837 } 838 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 839 840 _, remove, err := martian.TestContext(req, nil, nil) 841 if err != nil { 842 t.Fatalf("martian.TestContext(): got %v, want no error", err) 843 } 844 defer remove() 845 846 if err := logger.ModifyRequest(req); err != nil { 847 t.Fatalf("ModifyRequest(): got %v, want no error", err) 848 } 849 850 log := logger.Export().Log 851 852 for _, param := range log.Entries[0].Request.PostData.Params { 853 if param.Name == "first" { 854 if got, want := param.Value, "true"; got != want { 855 t.Fatalf("Params[%q].Value: got %s, want %s", param.Name, got, want) 856 } 857 } 858 859 if param.Name == "second" { 860 if got, want := param.Value, "false"; got != want { 861 t.Fatalf("Params[%q].Value: got %s, want %s", param.Name, got, want) 862 } 863 } 864 } 865 866 logger = NewLogger() 867 logger.SetOption(SkipPostDataLoggingForContentTypes("application/x-www-form-urlencoded")) 868 869 body = strings.NewReader("first=true&second=false") 870 req, err = http.NewRequest("POST", "http://example.com", body) 871 if err != nil { 872 t.Fatalf("http.NewRequest(): got %v, want no error", err) 873 } 874 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 875 876 _, remove, err = martian.TestContext(req, nil, nil) 877 if err != nil { 878 t.Fatalf("martian.TestContext(): got %v, want no error", err) 879 } 880 defer remove() 881 882 if err := logger.ModifyRequest(req); err != nil { 883 t.Fatalf("ModifyRequest(): got %v, want no error", err) 884 } 885 886 log = logger.Export().Log 887 if got, want := len(log.Entries[0].Request.PostData.Params), 0; got != want { 888 t.Fatalf("len(log.Entries[0].Request.PostData.Params): got %v, want %v", got, want) 889 } 890 } 891 892 func TestJSONMarshalPostData(t *testing.T) { 893 // Verify that encoding/json round-trips har.PostData with both text and binary data. 894 for _, text := range []string{"hello", string([]byte{150, 151, 152})} { 895 want := &PostData{ 896 MimeType: "m", 897 Params: []Param{{Name: "n", Value: "v"}}, 898 Text: text, 899 } 900 data, err := json.Marshal(want) 901 if err != nil { 902 t.Fatal(err) 903 } 904 var got PostData 905 if err := json.Unmarshal(data, &got); err != nil { 906 t.Fatal(err) 907 } 908 if !reflect.DeepEqual(&got, want) { 909 t.Errorf("got %+v, want %+v", &got, want) 910 } 911 } 912 } 913 914 func TestJSONMarshalContent(t *testing.T) { 915 testCases := []struct { 916 name string 917 text []byte 918 encoding string 919 }{ 920 { 921 name: "binary data with base64 encoding", 922 text: []byte{120, 31, 99, 3}, 923 encoding: "base64", 924 }, 925 { 926 name: "ascii data with no encoding", 927 text: []byte("hello martian"), 928 }, 929 { 930 name: "ascii data with base64 encoding", 931 text: []byte("hello martian"), 932 encoding: "base64", 933 }, 934 } 935 936 for _, c := range testCases { 937 want := Content{ 938 Size: int64(len(c.text)), 939 MimeType: "application/x-test", 940 Text: c.text, 941 Encoding: c.encoding, 942 } 943 data, err := json.Marshal(want) 944 if err != nil { 945 t.Fatal(err) 946 } 947 var got Content 948 if err := json.Unmarshal(data, &got); err != nil { 949 t.Fatal(err) 950 } 951 if !reflect.DeepEqual(got, want) { 952 t.Errorf("got %+v, want %+v", got, want) 953 } 954 } 955 }