test(19.3-06): unit tests for the review fixes
- TestCORSCredentialedOriginRules, TestCORSAnchoredPatternNoSuffixMatch (D-04) - TestAPIDocsCSPNoHostSource (D-17) - TestLoadCookieConfigProductionInferredSecure, TestZeroCookieConfigDefaults (D-03) - TestSiteCachePurgeWaitAndClose, TestSiteCacheBulkCommitCoalesced (D-10)
This commit is contained in:
@@ -717,3 +717,162 @@ func TestSiteCachePurgeAsyncCoalesced(t *testing.T) {
|
||||
}
|
||||
assertNoToken(t, logs)
|
||||
}
|
||||
|
||||
// blockingReceiver answers once release is closed (or the request ends).
|
||||
func blockingReceiver(t *testing.T) (*httptest.Server, func() []purgeHit, func()) {
|
||||
t.Helper()
|
||||
release := make(chan struct{})
|
||||
var once sync.Once
|
||||
srv, hits := purgeReceiver(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
select {
|
||||
case <-release:
|
||||
_, _ = w.Write([]byte(`{"purged":1}`))
|
||||
case <-r.Context().Done():
|
||||
}
|
||||
})
|
||||
free := func() { once.Do(func() { close(release) }) }
|
||||
t.Cleanup(free)
|
||||
return srv, hits, free
|
||||
}
|
||||
|
||||
func TestSiteCachePurgeWaitAndClose(t *testing.T) {
|
||||
t.Run("nil and idle purgers return at once", func(t *testing.T) {
|
||||
var nilPurger *SiteCachePurger
|
||||
if err := nilPurger.Wait(context.Background()); err != nil {
|
||||
t.Fatalf("nil Wait = %v", err)
|
||||
}
|
||||
srv, _ := purgeReceiver(t, func(http.ResponseWriter, *http.Request) {})
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
if err := newTestPurger(t, srv).Wait(ctx); err != nil {
|
||||
t.Fatalf("idle Wait under a cancelled context = %v, want nil", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Wait gives up with the context and the purge is still sent", func(t *testing.T) {
|
||||
captureLogs(t)
|
||||
srv, hits, free := blockingReceiver(t)
|
||||
p := newTestPurger(t, srv)
|
||||
PurgeSiteCacheAfterCommit(context.Background(), nil, p, "post", "pending")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)
|
||||
defer cancel()
|
||||
if err := p.Wait(ctx); !errors.Is(err, context.DeadlineExceeded) {
|
||||
t.Fatalf("Wait = %v, want context.DeadlineExceeded", err)
|
||||
}
|
||||
free()
|
||||
waitPurges(t, p)
|
||||
if got := hits(); len(got) != 1 || got[0].body["slug"] != "pending" {
|
||||
t.Fatalf("requests = %#v, want the queued purge", got)
|
||||
}
|
||||
})
|
||||
|
||||
install := func(t *testing.T, srv *httptest.Server) (*Handle, *SiteCachePurger) {
|
||||
t.Helper()
|
||||
cfg := testConfig(t)
|
||||
if err := cfg.Set(SiteCachePurgeURLKey, srv.URL+"/api/__site__/cache/purge"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cfg.Set(SiteCachePurgeTokenKey, purgeToken40); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app := backpack.New(cfg)
|
||||
h, err := Install(context.Background(), app)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := SiteCacheFromApp(app)
|
||||
if p == nil {
|
||||
t.Fatal("Install published no purger")
|
||||
}
|
||||
return h, p
|
||||
}
|
||||
|
||||
t.Run("Handle.Close waits for a queued purge", func(t *testing.T) {
|
||||
captureLogs(t)
|
||||
srv, hits := purgeReceiver(t, func(w http.ResponseWriter, _ *http.Request) {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
_, _ = w.Write([]byte(`{"purged":1}`))
|
||||
})
|
||||
h, p := install(t, srv)
|
||||
PurgeSiteCacheAfterCommit(context.Background(), nil, p, "post", "at-shutdown")
|
||||
if err := h.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := hits(); len(got) != 1 || got[0].body["slug"] != "at-shutdown" {
|
||||
t.Fatalf("requests after Close = %#v, want the queued purge", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Handle.Close is bounded when the site hangs", func(t *testing.T) {
|
||||
captureLogs(t)
|
||||
srv, _, _ := blockingReceiver(t)
|
||||
h, p := install(t, srv)
|
||||
PurgeSiteCacheAfterCommit(context.Background(), nil, p, "post", "hung")
|
||||
start := time.Now()
|
||||
if err := h.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if elapsed := time.Since(start); elapsed > SiteCachePurgeTimeout+time.Second+500*time.Millisecond {
|
||||
t.Fatalf("Close took %s, want at most %s plus a second", elapsed, SiteCachePurgeTimeout)
|
||||
}
|
||||
waitPurges(t, p)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSiteCacheBulkCommitCoalesced(t *testing.T) {
|
||||
gdb := purgeDB(t)
|
||||
captureLogs(t)
|
||||
ctx := context.Background()
|
||||
|
||||
run := func(t *testing.T, save func(p *SiteCachePurger) error, last string) {
|
||||
t.Helper()
|
||||
srv, hits, free := blockingReceiver(t)
|
||||
p := newTestPurger(t, srv)
|
||||
start := time.Now()
|
||||
if err := save(p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if elapsed := time.Since(start); elapsed > 500*time.Millisecond {
|
||||
t.Fatalf("the saves took %s while the site was blocked, want under 500ms", elapsed)
|
||||
}
|
||||
free()
|
||||
waitPurges(t, p)
|
||||
got := hits()
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("%d requests, want 2 (one in flight, one coalesced follow-up)", len(got))
|
||||
}
|
||||
if got[1].body["slug"] != last {
|
||||
t.Fatalf("follow-up slug = %q, want the last, %q", got[1].body["slug"], last)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("25 purges in one transaction", func(t *testing.T) {
|
||||
run(t, func(p *SiteCachePurger) error {
|
||||
return lagoon.Transaction(ctx, gdb, func(ctx context.Context, tx *gorm.DB) error {
|
||||
for i := range 25 {
|
||||
slug := "bulk-" + strconv.Itoa(i)
|
||||
if err := tx.Exec(`INSERT INTO purge_posts (slug) VALUES (?)`, slug).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
PurgeSiteCacheAfterCommit(ctx, tx, p, "post", slug)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}, "bulk-24")
|
||||
})
|
||||
|
||||
t.Run("10 separate transactions", func(t *testing.T) {
|
||||
run(t, func(p *SiteCachePurger) error {
|
||||
for i := range 10 {
|
||||
slug := "each-" + strconv.Itoa(i)
|
||||
if err := lagoon.Transaction(ctx, gdb, func(ctx context.Context, tx *gorm.DB) error {
|
||||
PurgeSiteCacheAfterCommit(ctx, tx, p, "post", slug)
|
||||
return tx.Exec(`INSERT INTO purge_posts (slug) VALUES (?)`, slug).Error
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, "each-9")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user