| 670 | } |
| 671 | |
| 672 | func TestServeContent(t *testing.T) { |
| 673 | defer afterTest(t) |
| 674 | type serveParam struct { |
| 675 | name string |
| 676 | modtime time.Time |
| 677 | content io.ReadSeeker |
| 678 | contentType string |
| 679 | etag string |
| 680 | } |
| 681 | servec := make(chan serveParam, 1) |
| 682 | lock := sync.Mutex{} |
| 683 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 684 | p := <-servec |
| 685 | if p.etag != "" { |
| 686 | w.Header().Set("ETag", p.etag) |
| 687 | } |
| 688 | if p.contentType != "" { |
| 689 | w.Header().Set("Content-Type", p.contentType) |
| 690 | } |
| 691 | lock.Lock() |
| 692 | defer lock.Unlock() |
| 693 | err := ServeContent(w, r, p.name, p.modtime, p.content) |
| 694 | if err != nil { |
| 695 | t.Fail() |
| 696 | } |
| 697 | })) |
| 698 | defer ts.Close() |
| 699 | |
| 700 | type testCase struct { |
| 701 | // One of file or content must be set: |
| 702 | file string |
| 703 | content io.ReadSeeker |
| 704 | |
| 705 | modtime time.Time |
| 706 | serveETag string // optional |
| 707 | serveContentType string // optional |
| 708 | reqHeader map[string]string |
| 709 | wantLastMod string |
| 710 | wantContentType string |
| 711 | wantStatus int |
| 712 | } |
| 713 | htmlModTime := mustStat(t, "testdata/index.html").ModTime() |
| 714 | tests := map[string]testCase{ |
| 715 | "no_last_modified": { |
| 716 | file: "testdata/style.css", |
| 717 | wantContentType: "text/css; charset=utf-8", |
| 718 | wantStatus: 200, |
| 719 | }, |
| 720 | "with_last_modified": { |
| 721 | file: "testdata/index.html", |
| 722 | wantContentType: "text/html; charset=utf-8", |
| 723 | modtime: htmlModTime, |
| 724 | wantLastMod: htmlModTime.UTC().Format(http.TimeFormat), |
| 725 | wantStatus: 200, |
| 726 | }, |
| 727 | "not_modified_modtime": { |
| 728 | file: "testdata/style.css", |
| 729 | modtime: htmlModTime, |