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  }