- pier: TestSessionReserve (A-WR-03), TestLockScope (A-WR-07), TestScopeWidening (A-WR-04), TestStatelessFanOut (A-WR-05, A-WR-06), TestPersonalTokenBinding (A-WR-09), TestDispatchHardening (A-WR-01, A-WR-02, A-WR-08, A-IN-04, A-IN-05, A-IN-08), TestCatalogPathFields (A-WR-02, A-IN-07), TestPromptWriteCeiling (C-IN-01), TestTokenScopedRevoke (B-WR-04, C-IN-02), TestResolveClientAddress (B-IN-04); test seam WrapStore - pact TestFrontendTokenScopes, towel TestClientIP, cabana TestTokenScopeNameParity - cabana TestAccountContributionURL (B-WR-03), TestAccountContributionsIsolation (B-WR-06, B-IN-03), TestRecordActionPromptLocalized (B-IN-02), and the Postgres TestAccountTokenRevokeEvent (B-WR-04) and TestResolveBackendTokenRemote (B-IN-04) - vitest: hotkeysEditing.test.ts (B-WR-01, B-WR-02) and the extended AccountContributions.test.ts (B-WR-03, B-WR-06, B-IN-01) - check-phase19.7.sh requires every name (GO_TESTS, GO_TAGGED_TESTS, DOCKER_TESTS, ADMIN_FILES) and scans the new files (PHASE_TEST_FILES)
92 lines
2.8 KiB
Go
92 lines
2.8 KiB
Go
package pier
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/bouncer"
|
|
"git.golem15.com/golem15/summercms/modules/cabana"
|
|
)
|
|
|
|
// Test seams (package pier, compiled into the test binary only).
|
|
|
|
// SetBackendTokens replaces the admin personal token resolver, which needs
|
|
// a database in production (cabana.ResolveBackendToken).
|
|
func (p *Pier) SetBackendTokens(fn func(ctx context.Context, app *backpack.App, raw string) (*bouncer.Principal, *cabana.BackendAPIToken, []string, error)) {
|
|
p.identities.backendTokens = fn
|
|
}
|
|
|
|
// Resolve resolves a bearer into an Identity as the endpoint does.
|
|
func (p *Pier) Resolve(ctx context.Context, raw string) (Identity, error) {
|
|
return p.identities.resolve(ctx, raw)
|
|
}
|
|
|
|
// Ceiling reports whether the read/write ceiling applies to the identity.
|
|
func (id Identity) Ceiling() bool { return id.ceiling }
|
|
|
|
// AdvanceStoreClock moves the memory session store's clock forward by d, so
|
|
// a test can expire idle sessions without waiting; a Redis store is moved
|
|
// with miniredis.FastForward instead.
|
|
func (p *Pier) AdvanceStoreClock(d time.Duration) bool {
|
|
ms, ok := p.store.(*memoryStore)
|
|
if !ok {
|
|
return false
|
|
}
|
|
ms.mu.Lock()
|
|
base := ms.now
|
|
ms.now = func() time.Time { return base().Add(d) }
|
|
ms.mu.Unlock()
|
|
return true
|
|
}
|
|
|
|
// StatelessServers counts the per-identity servers of the stateless path.
|
|
func (p *Pier) StatelessServers() int {
|
|
p.stateless.mu.Lock()
|
|
defer p.stateless.mu.Unlock()
|
|
return len(p.stateless.entries)
|
|
}
|
|
|
|
// SetRecheck sets how often a long GET stream re-verifies its bearer.
|
|
func (p *Pier) SetRecheck(d time.Duration) { p.recheck = d }
|
|
|
|
// ReapNow runs one session reaper pass and answers how many local sessions
|
|
// it closed.
|
|
func (p *Pier) ReapNow(ctx context.Context) int { return p.sessions.reapOnce(ctx) }
|
|
|
|
// LocalSessions counts the stateful sessions connected on this instance.
|
|
func (p *Pier) LocalSessions() int {
|
|
p.sessions.mu.Lock()
|
|
defer p.sessions.mu.Unlock()
|
|
return len(p.sessions.local)
|
|
}
|
|
|
|
// StopReaper ends the session reaper goroutine Mount started.
|
|
func (p *Pier) StopReaper() {
|
|
if p.stopReap != nil {
|
|
p.stopReap()
|
|
}
|
|
}
|
|
|
|
// SessionDone answers a channel closed once the local session's SDK server
|
|
// session has ended (ss.Wait returned), and false when the session is not
|
|
// connected on this instance.
|
|
func (p *Pier) SessionDone(sid string) (<-chan struct{}, bool) {
|
|
p.sessions.mu.Lock()
|
|
ls := p.sessions.local[sid]
|
|
p.sessions.mu.Unlock()
|
|
if ls == nil || ls.ss == nil {
|
|
return nil, false
|
|
}
|
|
done := make(chan struct{})
|
|
go func() {
|
|
_ = ls.ss.Wait()
|
|
close(done)
|
|
}()
|
|
return done, true
|
|
}
|
|
|
|
// WrapStore replaces the session store with wrap(current store), so a test
|
|
// can count calls or hide the store's optional capabilities.
|
|
func (p *Pier) WrapStore(wrap func(Store) Store) { p.store = wrap(p.store) }
|