Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d52cac1ec6 | ||
|
|
0f9b68a0e8 | ||
|
|
8cf5acaf1d |
@@ -181,6 +181,11 @@ func (r *recordingArchives) Renames() []archiveRename {
|
||||
return out
|
||||
}
|
||||
|
||||
// newTestApp returns an app whose RequireStart fails the test when
|
||||
// starting takes longer than fx's default start timeout of 15s. That
|
||||
// limit catches a start that hangs, not a busy host: measured with make
|
||||
// test on 2026-10-02 at host load 58-69 on 48 cores, the slowest of this
|
||||
// package's starts took 0.49s.
|
||||
func newTestApp(
|
||||
t *testing.T,
|
||||
targets ...any,
|
||||
|
||||
@@ -1911,9 +1911,13 @@ func (h *Handlers) HandleTargetToggle() http.HandlerFunc {
|
||||
return false, err
|
||||
}
|
||||
|
||||
tgt.Active = !tgt.Active
|
||||
// Only the active column: saving the whole row would
|
||||
// write back the name and settings read above over an
|
||||
// edit saved since.
|
||||
active := !tgt.Active
|
||||
|
||||
return tgt.Active, h.db.DB().Save(&tgt).Error
|
||||
return active, h.db.DB().Model(&tgt).
|
||||
Update("active", active).Error
|
||||
},
|
||||
"failed to toggle target",
|
||||
targetActivated, targetDeactivated,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// TestHandleTargetToggle_DoesNotUndoAnEdit proves that a toggle which
|
||||
// loaded the target before an edit of it was saved does not write the
|
||||
// old name and settings back over the edit. The edit is submitted from
|
||||
// a callback on the toggle's own read of the target, so it is saved
|
||||
// after that read and before the toggle writes.
|
||||
func TestHandleTargetToggle_DoesNotUndoAnEdit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
env := setupSourceTest(t)
|
||||
wh, tgt := seedHTTPTarget(t, env, "", "")
|
||||
require.True(t, tgt.Active)
|
||||
|
||||
var (
|
||||
edited bool
|
||||
editCode int
|
||||
)
|
||||
|
||||
require.NoError(t, env.db.DB().Callback().Query().
|
||||
After("gorm:query").
|
||||
Register("test:edit_after_toggle_read", func(tx *gorm.DB) {
|
||||
// The edit reads the target too; only the toggle's read,
|
||||
// the first, submits it.
|
||||
if tx.Statement.Table != "targets" || edited {
|
||||
return
|
||||
}
|
||||
|
||||
edited = true
|
||||
editCode = submitTargetEdit(
|
||||
env, wh.ID, tgt.ID,
|
||||
editForm(editReplacedURL, "", ""),
|
||||
).Code
|
||||
}),
|
||||
)
|
||||
|
||||
req := postRequest(
|
||||
"/hook/"+wh.ID+"/targets/"+tgt.ID+"/toggle",
|
||||
env.cookies,
|
||||
map[string]string{paramSourceID: wh.ID, paramTargetID: tgt.ID},
|
||||
)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
env.handlers.HandleTargetToggle().ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
require.Equal(t, http.StatusSeeOther, editCode)
|
||||
|
||||
stored := storedTarget(t, env, tgt.ID)
|
||||
assert.False(t, stored.Active)
|
||||
assert.Equal(t, "edited-name", stored.Name)
|
||||
assert.Equal(t, 5, stored.MaxRetries)
|
||||
assert.Equal(
|
||||
t, editReplacedURL, storedHTTPConfig(t, env, tgt.ID).URL,
|
||||
)
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
@@ -78,14 +77,7 @@ func newTestSessionManager(
|
||||
key[i] = byte(i)
|
||||
}
|
||||
|
||||
store := sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{
|
||||
Path: "/",
|
||||
MaxAge: 86400 * 7,
|
||||
HttpOnly: true,
|
||||
Secure: false,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
store := session.NewStore(key)
|
||||
|
||||
var now func() time.Time
|
||||
|
||||
@@ -931,8 +923,7 @@ func metricsAuthMiddleware(
|
||||
}
|
||||
|
||||
key := make([]byte, testKeySize)
|
||||
store := sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{Path: "/", MaxAge: 86400}
|
||||
store := session.NewStore(key)
|
||||
|
||||
sessManager := session.NewForTest(store, cfg, log, key, nil)
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package session
|
||||
|
||||
import "github.com/gorilla/sessions"
|
||||
|
||||
// NewStore exposes the production cookie-store constructor so tests
|
||||
// exercise the store the application actually runs with, rather than a
|
||||
// lookalike assembled in the test.
|
||||
func NewStore(key []byte) *sessions.CookieStore {
|
||||
return newStore(key)
|
||||
}
|
||||
@@ -8,6 +8,13 @@ import (
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
)
|
||||
|
||||
// NewStore exposes the production cookie-store constructor so tests
|
||||
// exercise the store the application actually runs with, rather than a
|
||||
// lookalike assembled in the test.
|
||||
func NewStore(key []byte) *sessions.CookieStore {
|
||||
return newStore(key)
|
||||
}
|
||||
|
||||
// NewForTest creates a Session with a pre-configured cookie store for use
|
||||
// in tests. This bypasses the fx lifecycle and database dependency, allowing
|
||||
// middleware and handler tests to use real session functionality. The key
|
||||
|
||||
+9
-3
@@ -2,9 +2,10 @@
|
||||
# script/test: run the test suite.
|
||||
#
|
||||
# -timeout is applied by `go test` per package, not to the run as a whole, so
|
||||
# it only has to clear the slowest single package. That is internal/handlers,
|
||||
# measured in a cache-defeated builder stage on the 48-core shared build host
|
||||
# (2026-08-18); load- and host-dependent, not invariants:
|
||||
# it only has to clear the slowest single package. When this budget was set
|
||||
# that was internal/handlers, measured in a cache-defeated builder stage on the
|
||||
# 48-core shared build host (2026-08-18); load- and host-dependent, not
|
||||
# invariants:
|
||||
#
|
||||
# 16.9s host load 5-20, GOMAXPROCS 48
|
||||
# 45.9s / 47.3s / 49.0s three runs at deliberate host load 31-73
|
||||
@@ -23,6 +24,11 @@
|
||||
# a condition CI runs under. If a CPU-limited runner ever puts a real run near
|
||||
# 67s, that is the datum to revisit the org figure with.
|
||||
#
|
||||
# Those figures predate tests hashing the admin password at 1 MB instead of
|
||||
# 64 MB (https://git.eeqj.de/sneak/webhooker/pulls/404). After that change, in
|
||||
# a cache-defeated build at host load 44-109 (2026-10-02), internal/handlers
|
||||
# took 8.5s and the slowest package was internal/database at 15.8s.
|
||||
#
|
||||
# -p 4 -parallel 8 keep the run under 2 GB of memory: at most four test
|
||||
# binaries build or run at once, each with at most eight parallel tests. Under
|
||||
# -race every test binary and every link costs a few hundred MB, so the
|
||||
|
||||
Reference in New Issue
Block a user