github.com/gofiber/fiber/v2@v2.47.0/middleware/etag/etag_test.go (about)

     1  package etag
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net/http/httptest"
     7  	"testing"
     8  
     9  	"github.com/gofiber/fiber/v2"
    10  	"github.com/gofiber/fiber/v2/utils"
    11  
    12  	"github.com/valyala/fasthttp"
    13  )
    14  
    15  // go test -run Test_ETag_Next
    16  func Test_ETag_Next(t *testing.T) {
    17  	t.Parallel()
    18  	app := fiber.New()
    19  	app.Use(New(Config{
    20  		Next: func(_ *fiber.Ctx) bool {
    21  			return true
    22  		},
    23  	}))
    24  
    25  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
    26  	utils.AssertEqual(t, nil, err)
    27  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
    28  }
    29  
    30  // go test -run Test_ETag_SkipError
    31  func Test_ETag_SkipError(t *testing.T) {
    32  	t.Parallel()
    33  	app := fiber.New()
    34  
    35  	app.Use(New())
    36  
    37  	app.Get("/", func(c *fiber.Ctx) error {
    38  		return fiber.ErrForbidden
    39  	})
    40  
    41  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
    42  	utils.AssertEqual(t, nil, err)
    43  	utils.AssertEqual(t, fiber.StatusForbidden, resp.StatusCode)
    44  }
    45  
    46  // go test -run Test_ETag_NotStatusOK
    47  func Test_ETag_NotStatusOK(t *testing.T) {
    48  	t.Parallel()
    49  	app := fiber.New()
    50  
    51  	app.Use(New())
    52  
    53  	app.Get("/", func(c *fiber.Ctx) error {
    54  		return c.SendStatus(fiber.StatusCreated)
    55  	})
    56  
    57  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
    58  	utils.AssertEqual(t, nil, err)
    59  	utils.AssertEqual(t, fiber.StatusCreated, resp.StatusCode)
    60  }
    61  
    62  // go test -run Test_ETag_NoBody
    63  func Test_ETag_NoBody(t *testing.T) {
    64  	t.Parallel()
    65  	app := fiber.New()
    66  
    67  	app.Use(New())
    68  
    69  	app.Get("/", func(c *fiber.Ctx) error {
    70  		return nil
    71  	})
    72  
    73  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
    74  	utils.AssertEqual(t, nil, err)
    75  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
    76  }
    77  
    78  // go test -run Test_ETag_NewEtag
    79  func Test_ETag_NewEtag(t *testing.T) {
    80  	t.Parallel()
    81  	t.Run("without HeaderIfNoneMatch", func(t *testing.T) {
    82  		t.Parallel()
    83  		testETagNewEtag(t, false, false)
    84  	})
    85  	t.Run("with HeaderIfNoneMatch and not matched", func(t *testing.T) {
    86  		t.Parallel()
    87  		testETagNewEtag(t, true, false)
    88  	})
    89  	t.Run("with HeaderIfNoneMatch and matched", func(t *testing.T) {
    90  		t.Parallel()
    91  		testETagNewEtag(t, true, true)
    92  	})
    93  }
    94  
    95  func testETagNewEtag(t *testing.T, headerIfNoneMatch, matched bool) { //nolint:revive // We're in a test, so using bools as a flow-control is fine
    96  	t.Helper()
    97  
    98  	app := fiber.New()
    99  
   100  	app.Use(New())
   101  
   102  	app.Get("/", func(c *fiber.Ctx) error {
   103  		return c.SendString("Hello, World!")
   104  	})
   105  
   106  	req := httptest.NewRequest(fiber.MethodGet, "/", nil)
   107  	if headerIfNoneMatch {
   108  		etag := `"non-match"`
   109  		if matched {
   110  			etag = `"13-1831710635"`
   111  		}
   112  		req.Header.Set(fiber.HeaderIfNoneMatch, etag)
   113  	}
   114  
   115  	resp, err := app.Test(req)
   116  	utils.AssertEqual(t, nil, err)
   117  
   118  	if !headerIfNoneMatch || !matched {
   119  		utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   120  		utils.AssertEqual(t, `"13-1831710635"`, resp.Header.Get(fiber.HeaderETag))
   121  		return
   122  	}
   123  
   124  	if matched {
   125  		utils.AssertEqual(t, fiber.StatusNotModified, resp.StatusCode)
   126  		b, err := io.ReadAll(resp.Body)
   127  		utils.AssertEqual(t, nil, err)
   128  		utils.AssertEqual(t, 0, len(b))
   129  	}
   130  }
   131  
   132  // go test -run Test_ETag_WeakEtag
   133  func Test_ETag_WeakEtag(t *testing.T) {
   134  	t.Parallel()
   135  	t.Run("without HeaderIfNoneMatch", func(t *testing.T) {
   136  		t.Parallel()
   137  		testETagWeakEtag(t, false, false)
   138  	})
   139  	t.Run("with HeaderIfNoneMatch and not matched", func(t *testing.T) {
   140  		t.Parallel()
   141  		testETagWeakEtag(t, true, false)
   142  	})
   143  	t.Run("with HeaderIfNoneMatch and matched", func(t *testing.T) {
   144  		t.Parallel()
   145  		testETagWeakEtag(t, true, true)
   146  	})
   147  }
   148  
   149  func testETagWeakEtag(t *testing.T, headerIfNoneMatch, matched bool) { //nolint:revive // We're in a test, so using bools as a flow-control is fine
   150  	t.Helper()
   151  
   152  	app := fiber.New()
   153  
   154  	app.Use(New(Config{Weak: true}))
   155  
   156  	app.Get("/", func(c *fiber.Ctx) error {
   157  		return c.SendString("Hello, World!")
   158  	})
   159  
   160  	req := httptest.NewRequest(fiber.MethodGet, "/", nil)
   161  	if headerIfNoneMatch {
   162  		etag := `W/"non-match"`
   163  		if matched {
   164  			etag = `W/"13-1831710635"`
   165  		}
   166  		req.Header.Set(fiber.HeaderIfNoneMatch, etag)
   167  	}
   168  
   169  	resp, err := app.Test(req)
   170  	utils.AssertEqual(t, nil, err)
   171  
   172  	if !headerIfNoneMatch || !matched {
   173  		utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   174  		utils.AssertEqual(t, `W/"13-1831710635"`, resp.Header.Get(fiber.HeaderETag))
   175  		return
   176  	}
   177  
   178  	if matched {
   179  		utils.AssertEqual(t, fiber.StatusNotModified, resp.StatusCode)
   180  		b, err := io.ReadAll(resp.Body)
   181  		utils.AssertEqual(t, nil, err)
   182  		utils.AssertEqual(t, 0, len(b))
   183  	}
   184  }
   185  
   186  // go test -run Test_ETag_CustomEtag
   187  func Test_ETag_CustomEtag(t *testing.T) {
   188  	t.Parallel()
   189  	t.Run("without HeaderIfNoneMatch", func(t *testing.T) {
   190  		t.Parallel()
   191  		testETagCustomEtag(t, false, false)
   192  	})
   193  	t.Run("with HeaderIfNoneMatch and not matched", func(t *testing.T) {
   194  		t.Parallel()
   195  		testETagCustomEtag(t, true, false)
   196  	})
   197  	t.Run("with HeaderIfNoneMatch and matched", func(t *testing.T) {
   198  		t.Parallel()
   199  		testETagCustomEtag(t, true, true)
   200  	})
   201  }
   202  
   203  func testETagCustomEtag(t *testing.T, headerIfNoneMatch, matched bool) { //nolint:revive // We're in a test, so using bools as a flow-control is fine
   204  	t.Helper()
   205  
   206  	app := fiber.New()
   207  
   208  	app.Use(New())
   209  
   210  	app.Get("/", func(c *fiber.Ctx) error {
   211  		c.Set(fiber.HeaderETag, `"custom"`)
   212  		if bytes.Equal(c.Request().Header.Peek(fiber.HeaderIfNoneMatch), []byte(`"custom"`)) {
   213  			return c.SendStatus(fiber.StatusNotModified)
   214  		}
   215  		return c.SendString("Hello, World!")
   216  	})
   217  
   218  	req := httptest.NewRequest(fiber.MethodGet, "/", nil)
   219  	if headerIfNoneMatch {
   220  		etag := `"non-match"`
   221  		if matched {
   222  			etag = `"custom"`
   223  		}
   224  		req.Header.Set(fiber.HeaderIfNoneMatch, etag)
   225  	}
   226  
   227  	resp, err := app.Test(req)
   228  	utils.AssertEqual(t, nil, err)
   229  
   230  	if !headerIfNoneMatch || !matched {
   231  		utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   232  		utils.AssertEqual(t, `"custom"`, resp.Header.Get(fiber.HeaderETag))
   233  		return
   234  	}
   235  
   236  	if matched {
   237  		utils.AssertEqual(t, fiber.StatusNotModified, resp.StatusCode)
   238  		b, err := io.ReadAll(resp.Body)
   239  		utils.AssertEqual(t, nil, err)
   240  		utils.AssertEqual(t, 0, len(b))
   241  	}
   242  }
   243  
   244  // go test -run Test_ETag_CustomEtagPut
   245  func Test_ETag_CustomEtagPut(t *testing.T) {
   246  	t.Parallel()
   247  	app := fiber.New()
   248  
   249  	app.Use(New())
   250  
   251  	app.Put("/", func(c *fiber.Ctx) error {
   252  		c.Set(fiber.HeaderETag, `"custom"`)
   253  		if !bytes.Equal(c.Request().Header.Peek(fiber.HeaderIfMatch), []byte(`"custom"`)) {
   254  			return c.SendStatus(fiber.StatusPreconditionFailed)
   255  		}
   256  		return c.SendString("Hello, World!")
   257  	})
   258  
   259  	req := httptest.NewRequest(fiber.MethodPut, "/", nil)
   260  	req.Header.Set(fiber.HeaderIfMatch, `"non-match"`)
   261  	resp, err := app.Test(req)
   262  	utils.AssertEqual(t, nil, err)
   263  	utils.AssertEqual(t, fiber.StatusPreconditionFailed, resp.StatusCode)
   264  }
   265  
   266  // go test -v -run=^$ -bench=Benchmark_Etag -benchmem -count=4
   267  func Benchmark_Etag(b *testing.B) {
   268  	app := fiber.New()
   269  
   270  	app.Use(New())
   271  
   272  	app.Get("/", func(c *fiber.Ctx) error {
   273  		return c.SendString("Hello, World!")
   274  	})
   275  
   276  	h := app.Handler()
   277  
   278  	fctx := &fasthttp.RequestCtx{}
   279  	fctx.Request.Header.SetMethod(fiber.MethodGet)
   280  	fctx.Request.SetRequestURI("/")
   281  
   282  	b.ReportAllocs()
   283  	b.ResetTimer()
   284  
   285  	for n := 0; n < b.N; n++ {
   286  		h(fctx)
   287  	}
   288  
   289  	utils.AssertEqual(b, 200, fctx.Response.Header.StatusCode())
   290  	utils.AssertEqual(b, `"13-1831710635"`, string(fctx.Response.Header.Peek(fiber.HeaderETag)))
   291  }