httpgzip - fileserver_test.go
1 package httpgzip
2
3 import (
4 "bytes"
5 "compress/gzip"
6 "io"
7 "io/fs"
8 "net/http"
9 "net/http/httptest"
10 "testing"
11 "time"
12 )
13
14 type stat int64
15
16 func (stat) Name() string {
17 return ""
18 }
19
20 func (s stat) Size() int64 {
21 return int64(s)
22 }
23
24 func (stat) Mode() fs.FileMode {
25 return 0
26 }
27
28 func (stat) ModTime() time.Time {
29 return time.Now()
30 }
31
32 func (stat) IsDir() bool {
33 return false
34 }
35
36 func (stat) Sys() any {
37 return nil
38 }
39
40 type file struct {
41 *bytes.Reader
42 }
43
44 func (f *file) Close() error {
45 return nil
46 }
47
48 func (f *file) Readdir(count int) ([]fs.FileInfo, error) {
49 return nil, nil
50 }
51
52 func (f *file) Stat() (fs.FileInfo, error) {
53 return stat(f.Size()), nil
54 }
55
56 type memFS map[string][]byte
57
58 func (m memFS) Open(name string) (http.File, error) {
59 f, ok := m[name]
60 if !ok {
61 return nil, fs.ErrNotExist
62 }
63
64 return &file{Reader: bytes.NewReader(f)}, nil
65 }
66
67 func gzipContent(content string) []byte {
68 var buf bytes.Buffer
69
70 g := gzip.NewWriter(&buf)
71
72 io.WriteString(g, content)
73
74 g.Close()
75
76 return buf.Bytes()
77 }
78
79 func TestFileserver(t *testing.T) {
80 srv := httptest.NewServer(FileServer(memFS{
81 "/file.txt": []byte("content"),
82 "/anotherFile.txt": []byte("Hello, World!"),
83 "/some_file": []byte("<HTML>"),
84 }, memFS{
85 "/anotherFile.txt.gz": gzipContent("Foo Bar"),
86 "/some_file.gz": gzipContent("<HTML>"),
87 }))
88 client := srv.Client()
89
90 for n, test := range [...]struct {
91 name string
92 identityContent string
93 content string
94 contentType string
95 }{
96 {
97 name: "/unknown",
98 },
99 {
100 name: "/file.txt",
101 identityContent: "content",
102 content: "content",
103 contentType: "text/plain; charset=utf-8",
104 },
105 {
106 name: "/anotherFile.txt",
107 identityContent: "Hello, World!",
108 content: "Foo Bar",
109 contentType: "text/plain; charset=utf-8",
110 },
111 {
112 name: "/some_file",
113 identityContent: "<HTML>",
114 content: "<HTML>",
115 contentType: "text/html; charset=utf-8",
116 },
117 } {
118 testFile(t, client, n+1, 1, srv.URL+test.name, test.identityContent, test.contentType)
119 testFile(t, client, n+1, 2, srv.URL+test.name, test.content, test.contentType)
120 }
121 }
122
123 func testFile(t *testing.T, client *http.Client, test, part int, url, content, contentType string) {
124 var resp *http.Response
125
126 if part == 1 {
127 req, _ := http.NewRequest(http.MethodGet, url, nil)
128 req.Header.Set("Accept-Encoding", "identity")
129
130 resp, _ = client.Do(req)
131 } else {
132 resp, _ = client.Get(url)
133 }
134
135 if content == "" {
136 if resp.StatusCode != http.StatusNotFound {
137 t.Errorf("test %d.%d: expecting status 404, got %d", test, part, resp.StatusCode)
138 }
139
140 return
141 }
142
143 if ct := resp.Header.Get("Content-Type"); ct != contentType {
144 t.Errorf("test %d.%d.1: expecting content type %q, got %q", test, part, contentType, ct)
145 } else if body, _ := io.ReadAll(resp.Body); string(body) != content {
146 t.Errorf("test %d.%d.2: expecting content %q, got %q", test, part, content, body)
147 }
148 }
149