goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/middleware/compress/compress_test.go (about) 1 package compress 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "io" 7 "net/http" 8 "net/http/httptest" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "goyave.dev/goyave/v5" 14 "goyave.dev/goyave/v5/config" 15 "goyave.dev/goyave/v5/util/fsutil/osfs" 16 "goyave.dev/goyave/v5/util/testutil" 17 ) 18 19 type closeableChildWriter struct { 20 io.Writer 21 closed bool 22 preWritten bool 23 } 24 25 func (w *closeableChildWriter) PreWrite(b []byte) { 26 w.preWritten = true 27 if pr, ok := w.Writer.(goyave.PreWriter); ok { 28 pr.PreWrite(b) 29 } 30 } 31 32 func (w *closeableChildWriter) Close() error { 33 w.closed = true 34 if wr, ok := w.Writer.(io.Closer); ok { 35 return wr.Close() 36 } 37 return nil 38 } 39 40 func TestCompressMiddleware(t *testing.T) { 41 42 server := testutil.NewTestServerWithOptions(t, goyave.Options{Config: config.LoadDefault()}) 43 44 handler := func(resp *goyave.Response, _ *goyave.Request) { 45 resp.Header().Set("Content-Length", "1234") 46 resp.String(http.StatusOK, "hello world") 47 } 48 49 compressMiddleware := &Middleware{ 50 Encoders: []Encoder{ 51 &Gzip{Level: gzip.BestCompression}, 52 }, 53 } 54 55 t.Run("No compression", func(t *testing.T) { 56 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 57 58 result := server.TestMiddleware(compressMiddleware, request, handler) 59 60 body, err := io.ReadAll(result.Body) 61 if err != nil { 62 panic(err) 63 } 64 assert.NoError(t, result.Body.Close()) 65 assert.Equal(t, "hello world", string(body)) // Not compressed 66 assert.NotEqual(t, "gzip", result.Header.Get("Content-Encoding")) 67 assert.Equal(t, "1234", result.Header.Get("Content-Length")) 68 assert.Equal(t, http.StatusOK, result.StatusCode) 69 }) 70 71 t.Run("Gzip", func(t *testing.T) { 72 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 73 request.Header().Set("Accept-Encoding", "gzip") 74 result := server.TestMiddleware(compressMiddleware, request, handler) 75 76 reader, err := gzip.NewReader(result.Body) 77 if err != nil { 78 panic(err) 79 } 80 body, err := io.ReadAll(reader) 81 if err != nil { 82 panic(err) 83 } 84 assert.NoError(t, result.Body.Close()) 85 assert.Equal(t, "hello world", string(body)) 86 assert.Equal(t, "gzip", result.Header.Get("Content-Encoding")) 87 assert.Empty(t, result.Header.Get("Content-Length")) 88 }) 89 90 t.Run("Accept all", func(t *testing.T) { 91 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 92 request.Header().Set("Accept-Encoding", "*") 93 result := server.TestMiddleware(compressMiddleware, request, handler) 94 95 assert.Equal(t, "gzip", result.Header.Get("Content-Encoding")) 96 97 reader, err := gzip.NewReader(result.Body) 98 if err != nil { 99 panic(err) 100 } 101 body, err := io.ReadAll(reader) 102 if err != nil { 103 panic(err) 104 } 105 assert.NoError(t, result.Body.Close()) 106 assert.Equal(t, "hello world", string(body)) 107 assert.Empty(t, result.Header.Get("Content-Length")) 108 }) 109 110 t.Run("Unsupported encoding", func(t *testing.T) { 111 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 112 request.Header().Set("Accept-Encoding", "bz") 113 114 result := server.TestMiddleware(compressMiddleware, request, handler) 115 116 body, err := io.ReadAll(result.Body) 117 if err != nil { 118 panic(err) 119 } 120 assert.NoError(t, result.Body.Close()) 121 assert.Equal(t, "hello world", string(body)) // Not compressed 122 assert.Empty(t, result.Header.Get("Content-Encoding")) 123 assert.Equal(t, http.StatusOK, result.StatusCode) 124 }) 125 126 t.Run("Upgrade", func(t *testing.T) { 127 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 128 request.Header().Set("Accept-Encoding", "gzip") 129 request.Header().Set("Upgrade", "example/1, foo/2") 130 131 result := server.TestMiddleware(compressMiddleware, request, handler) 132 133 body, err := io.ReadAll(result.Body) 134 if err != nil { 135 panic(err) 136 } 137 assert.NoError(t, result.Body.Close()) 138 assert.Equal(t, "hello world", string(body)) // Not compressed 139 assert.NotEqual(t, "gzip", result.Header.Get("Content-Encoding")) 140 assert.Equal(t, "1234", result.Header.Get("Content-Length")) 141 assert.Equal(t, http.StatusOK, result.StatusCode) 142 }) 143 144 t.Run("Write file", func(t *testing.T) { 145 request := testutil.NewTestRequest(http.MethodGet, "/gzip", nil) 146 request.Header().Set("Accept-Encoding", "gzip") 147 result := server.TestMiddleware(compressMiddleware, request, func(r *goyave.Response, _ *goyave.Request) { 148 r.File(&osfs.FS{}, "../../resources/custom_config.json") 149 }) 150 151 reader, err := gzip.NewReader(result.Body) 152 if err != nil { 153 panic(err) 154 } 155 body, err := io.ReadAll(reader) 156 if err != nil { 157 panic(err) 158 } 159 assert.NoError(t, result.Body.Close()) 160 assert.Equal(t, "gzip", result.Header.Get("Content-Encoding")) 161 assert.Empty(t, result.Header.Get("Content-Length")) 162 assert.Equal(t, "application/json", result.Header.Get("Content-Type")) 163 assert.Equal(t, "{\n \"custom-entry\": \"value\"\n}", string(body)) 164 }) 165 166 } 167 168 func TestGzipEncoder(t *testing.T) { 169 encoder := &Gzip{ 170 Level: gzip.BestCompression, 171 } 172 assert.Equal(t, "gzip", encoder.Encoding()) 173 assert.Equal(t, gzip.BestCompression, encoder.Level) 174 175 buf := bytes.NewBuffer([]byte{}) 176 writer := encoder.NewWriter(buf) 177 if assert.NotNil(t, writer) { 178 _, ok := writer.(*gzip.Writer) 179 assert.True(t, ok) 180 } 181 182 assert.Panics(t, func() { 183 // Invalid level 184 encoder := &Gzip{ 185 Level: -3, 186 } 187 encoder.NewWriter(bytes.NewBuffer([]byte{})) 188 }) 189 } 190 191 func TestCompressWriter(t *testing.T) { 192 encoder := &Gzip{ 193 Level: gzip.BestCompression, 194 } 195 196 buf := bytes.NewBuffer([]byte{}) 197 closeableWriter := &closeableChildWriter{ 198 Writer: buf, 199 closed: false, 200 } 201 202 response := httptest.NewRecorder() 203 204 writer := &compressWriter{ 205 WriteCloser: encoder.NewWriter(closeableWriter), 206 ResponseWriter: response, 207 childWriter: closeableWriter, 208 } 209 210 writer.PreWrite([]byte("hello world")) 211 212 assert.True(t, closeableWriter.preWritten) 213 214 require.NoError(t, writer.Close()) 215 assert.True(t, closeableWriter.closed) 216 }