test(19.3-06): wait for the queued site-cache purge before asserting (WR-01)
- every read of the purge receiver first drains the app's purger through cooler.SiteCachePurger.Wait, since cooler now queues purges after commit
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -206,10 +207,16 @@ func TestSiteCachePurgeRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("outside a transaction the after-commit purge runs at once", func(t *testing.T) {
|
t.Run("outside a transaction the after-commit purge is queued at once", func(t *testing.T) {
|
||||||
captureLogs(t)
|
captureLogs(t)
|
||||||
srv, hits := purgeReceiver(t, func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(`{"purged":2}`)) })
|
srv, hits := purgeReceiver(t, func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(`{"purged":2}`)) })
|
||||||
PurgeSiteCacheAfterCommit(context.Background(), nil, newTestPurger(t, srv), "category", "now")
|
p := newTestPurger(t, srv)
|
||||||
|
PurgeSiteCacheAfterCommit(context.Background(), nil, p, "category", "now")
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := p.Wait(ctx); err != nil {
|
||||||
|
t.Fatalf("Wait: %v", err)
|
||||||
|
}
|
||||||
if got := hits(); len(got) != 1 || got[0].body["kind"] != "category" || got[0].body["slug"] != "now" {
|
if got := hits(); len(got) != 1 || got[0].body["kind"] != "category" || got[0].body["slug"] != "now" {
|
||||||
t.Fatalf("requests = %#v, want one", got)
|
t.Fatalf("requests = %#v, want one", got)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package journal_test
|
package journal_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -9,9 +10,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.golem15.com/golem15/sm-journal-plugin/controllers"
|
"git.golem15.com/golem15/sm-journal-plugin/controllers"
|
||||||
"git.golem15.com/golem15/sm-journal-plugin/models"
|
"git.golem15.com/golem15/sm-journal-plugin/models"
|
||||||
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||||
|
"git.golem15.com/golem15/summercms/modules/cooler"
|
||||||
)
|
)
|
||||||
|
|
||||||
// purgeTestToken is a 40-character purge token for the receiver.
|
// purgeTestToken is a 40-character purge token for the receiver.
|
||||||
@@ -38,6 +42,9 @@ type purgeReceiver struct {
|
|||||||
got []purgeRequest
|
got []purgeRequest
|
||||||
status int
|
status int
|
||||||
probe func() string
|
probe func() string
|
||||||
|
// drain waits for the queued purges of the app under test; see
|
||||||
|
// drainFrom.
|
||||||
|
drain func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPurgeReceiver(t *testing.T) *purgeReceiver {
|
func newPurgeReceiver(t *testing.T) *purgeReceiver {
|
||||||
@@ -82,8 +89,15 @@ func (r *purgeReceiver) env() []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take returns the requests received so far and forgets them.
|
// take returns the requests received so far and forgets them, after
|
||||||
|
// draining the queued purges (see drainFrom).
|
||||||
func (r *purgeReceiver) take() []purgeRequest {
|
func (r *purgeReceiver) take() []purgeRequest {
|
||||||
|
r.mu.Lock()
|
||||||
|
drain := r.drain
|
||||||
|
r.mu.Unlock()
|
||||||
|
if drain != nil {
|
||||||
|
drain()
|
||||||
|
}
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
got := r.got
|
got := r.got
|
||||||
@@ -91,6 +105,21 @@ func (r *purgeReceiver) take() []purgeRequest {
|
|||||||
return got
|
return got
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drainFrom makes every read of r first wait for the purges queued on app's
|
||||||
|
// site-cache purger: cooler queues them after commit and sends them in the
|
||||||
|
// background, so a save's purge is asserted only once it was sent.
|
||||||
|
func (r *purgeReceiver) drainFrom(t *testing.T, app *backpack.App) {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
r.drain = func() {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := cooler.SiteCacheFromApp(app).Wait(ctx); err != nil {
|
||||||
|
t.Errorf("waiting for the queued site-cache purge: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *purgeReceiver) setStatus(status int) {
|
func (r *purgeReceiver) setStatus(status int) {
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
r.status = status
|
r.status = status
|
||||||
@@ -133,6 +162,7 @@ func (r *purgeReceiver) expectOnePurge(t *testing.T, stage, kind, slug string) p
|
|||||||
func TestCategoriesAdminPurgesSiteCache(t *testing.T) {
|
func TestCategoriesAdminPurgesSiteCache(t *testing.T) {
|
||||||
recv := newPurgeReceiver(t)
|
recv := newPurgeReceiver(t)
|
||||||
env := newPostsEnv(t, recv.env()...)
|
env := newPostsEnv(t, recv.env()...)
|
||||||
|
recv.drainFrom(t, env.app)
|
||||||
token := env.admin(t, controllers.PermissionAccessCategories)
|
token := env.admin(t, controllers.PermissionAccessCategories)
|
||||||
|
|
||||||
// The probe reads the committed row through the pool while the purge
|
// The probe reads the committed row through the pool while the purge
|
||||||
@@ -210,6 +240,7 @@ func TestCategoriesAdminPurgesSiteCache(t *testing.T) {
|
|||||||
func TestPostsAdminPurgesSiteCache(t *testing.T) {
|
func TestPostsAdminPurgesSiteCache(t *testing.T) {
|
||||||
recv := newPurgeReceiver(t)
|
recv := newPurgeReceiver(t)
|
||||||
env := newPostsEnv(t, recv.env()...)
|
env := newPostsEnv(t, recv.env()...)
|
||||||
|
recv.drainFrom(t, env.app)
|
||||||
token := env.admin(t, controllers.PermissionAccessPosts)
|
token := env.admin(t, controllers.PermissionAccessPosts)
|
||||||
|
|
||||||
recv.setProbe(func() string {
|
recv.setProbe(func() string {
|
||||||
@@ -340,6 +371,8 @@ func TestCategoriesAdminFrameworkKeysWin(t *testing.T) {
|
|||||||
"SUMMER_SITE_CACHE__PURGE_URL="+framework.srv.URL+"/api/__site__/cache/purge",
|
"SUMMER_SITE_CACHE__PURGE_URL="+framework.srv.URL+"/api/__site__/cache/purge",
|
||||||
"SUMMER_SITE_CACHE__PURGE_TOKEN="+purgeTestToken,
|
"SUMMER_SITE_CACHE__PURGE_TOKEN="+purgeTestToken,
|
||||||
)...)
|
)...)
|
||||||
|
framework.drainFrom(t, env.app)
|
||||||
|
alias.drainFrom(t, env.app)
|
||||||
token := env.admin(t, controllers.PermissionAccessCategories)
|
token := env.admin(t, controllers.PermissionAccessCategories)
|
||||||
env.expect(t, http.StatusCreated, http.MethodPost, adminAPI(adminCategoriesPath), token, map[string]any{
|
env.expect(t, http.StatusCreated, http.MethodPost, adminAPI(adminCategoriesPath), token, map[string]any{
|
||||||
"name": map[string]any{"en": "Framework keys"},
|
"name": map[string]any{"en": "Framework keys"},
|
||||||
|
|||||||
Reference in New Issue
Block a user