Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/tenantpool/manager_test.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/platform/tenantpool/manager_test.go |
| Original SHA-256 | 572322193edd336f3388a40bba1074b605169df7d1cf56c6a58a9729f27aa66b |
| Git blob SHA | 46021ea38136401104445a29246dcdbc31b3d9a7 |
| Reading-copy SHA-256 | 572322193edd336f3388a40bba1074b605169df7d1cf56c6a58a9729f27aa66b |
Every recorded occurrence
These 4 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / internal/platform/tenantpool/manager_test.go | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / internal/platform/tenantpool/manager_test.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/platform/tenantpool/manager_test.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/platform/tenantpool/manager_test.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
Recovered source transcript
Download complete source text ↓262 lines · 7.5 KB
package tenantpool
import (
"context"
"errors"
"fmt"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/google/uuid"
"github.com/missionworkforce/missionmatch/internal/platform/directory"
"github.com/missionworkforce/missionmatch/internal/platform/tenant"
)
// clock is a manual time source so LRU and idle eviction are deterministic.
type clock struct {
mu sync.Mutex
t time.Time
}
func (c *clock) now() time.Time { c.mu.Lock(); defer c.mu.Unlock(); return c.t }
func (c *clock) advance(d time.Duration) {
c.mu.Lock()
c.t = c.t.Add(d)
c.mu.Unlock()
}
// fakeBuild stands in for the real open and verify path; it records build calls and per tenant closes.
type fakeBuild struct {
mu sync.Mutex
calls int32
closes map[uuid.UUID]int
failFor map[uuid.UUID]error
delay time.Duration
}
func newFakeBuild() *fakeBuild {
return &fakeBuild{closes: map[uuid.UUID]int{}, failFor: map[uuid.UUID]error{}}
}
func (f *fakeBuild) build(_ context.Context, tc directory.TenantConn) (*opened, error) {
if f.delay > 0 {
time.Sleep(f.delay)
}
atomic.AddInt32(&f.calls, 1)
org := tc.OrganizationID
f.mu.Lock()
failErr := f.failFor[org]
f.mu.Unlock()
if failErr != nil {
return nil, failErr
}
return &opened{
db: &tenant.DB{}, // nil pool; the registry never touches Pool, only routes db and calls close
close: func() { f.mu.Lock(); f.closes[org]++; f.mu.Unlock() },
ref: tc.SecretRef,
}, nil
}
func (f *fakeBuild) closeCount(org uuid.UUID) int {
f.mu.Lock()
defer f.mu.Unlock()
return f.closes[org]
}
func mapLookup(tcs map[uuid.UUID]directory.TenantConn) func(context.Context, uuid.UUID) (directory.TenantConn, error) {
return func(_ context.Context, org uuid.UUID) (directory.TenantConn, error) {
tc, ok := tcs[org]
if !ok {
return directory.TenantConn{}, fmt.Errorf("%w: %s", directory.ErrUnknownTenant, org)
}
return tc, nil
}
}
func active(org uuid.UUID) directory.TenantConn {
return directory.TenantConn{OrganizationID: org, SecretRef: "ref-" + org.String()[:4], Status: directory.StatusActive}
}
func newTestManager(maxPools int, lookup func(context.Context, uuid.UUID) (directory.TenantConn, error), build func(context.Context, directory.TenantConn) (*opened, error)) *Manager {
return &Manager{
lookup: lookup,
build: build,
maxPools: maxPools,
now: time.Now,
pools: map[uuid.UUID]*entry{},
stop: make(chan struct{}),
}
}
func TestLazyOpenAndCacheHit(t *testing.T) {
org := uuid.New()
fb := newFakeBuild()
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{org: active(org)}), fb.build)
ctx := context.Background()
_, rel1, err := m.Acquire(ctx, org)
if err != nil {
t.Fatalf("first acquire: %v", err)
}
_, rel2, err := m.Acquire(ctx, org)
if err != nil {
t.Fatalf("second acquire: %v", err)
}
if got := atomic.LoadInt32(&fb.calls); got != 1 {
t.Fatalf("a tenant pool must open exactly once and be cached, build calls = %d", got)
}
if m.Len() != 1 {
t.Fatalf("one live pool expected, got %d", m.Len())
}
rel1()
rel2()
}
func TestUnknownTenantIsTyped(t *testing.T) {
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{}), newFakeBuild().build)
_, _, err := m.Acquire(context.Background(), uuid.New())
if !errors.Is(err, directory.ErrUnknownTenant) {
t.Fatalf("unknown tenant must be directory.ErrUnknownTenant, got %v", err)
}
}
func TestInactiveStatusRefuses(t *testing.T) {
org := uuid.New()
tc := active(org)
tc.Status = directory.StatusMigrating
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{org: tc}), newFakeBuild().build)
_, _, err := m.Acquire(context.Background(), org)
if !errors.Is(err, ErrTenantUnavailable) {
t.Fatalf("a non active tenant must be ErrTenantUnavailable, got %v", err)
}
}
func TestUnreachableBuildIsTyped(t *testing.T) {
org := uuid.New()
fb := newFakeBuild()
fb.failFor[org] = fmt.Errorf("%w: dial refused", ErrTenantUnreachable)
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{org: active(org)}), fb.build)
_, _, err := m.Acquire(context.Background(), org)
if !errors.Is(err, ErrTenantUnreachable) {
t.Fatalf("an unreachable tenant must be ErrTenantUnreachable, got %v", err)
}
}
func TestSingleflightOpensOnce(t *testing.T) {
org := uuid.New()
fb := newFakeBuild()
fb.delay = 20 * time.Millisecond
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{org: active(org)}), fb.build)
ctx := context.Background()
var wg sync.WaitGroup
for i := 0; i < 16; i++ {
wg.Add(1)
go func() {
defer wg.Done()
_, rel, err := m.Acquire(ctx, org)
if err != nil {
t.Errorf("concurrent acquire: %v", err)
return
}
rel()
}()
}
wg.Wait()
if got := atomic.LoadInt32(&fb.calls); got != 1 {
t.Fatalf("singleflight must open exactly one pool under concurrency, build calls = %d", got)
}
if m.Len() != 1 {
t.Fatalf("one live pool expected, got %d", m.Len())
}
}
func TestLRUEvictionClosesUnpinned(t *testing.T) {
a, b, c := uuid.New(), uuid.New(), uuid.New()
fb := newFakeBuild()
clk := &clock{t: time.Unix(1000, 0)}
m := newTestManager(2, mapLookup(map[uuid.UUID]directory.TenantConn{a: active(a), b: active(b), c: active(c)}), fb.build)
m.now = clk.now
ctx := context.Background()
clk.advance(time.Second)
_, relA, _ := m.Acquire(ctx, a)
relA()
clk.advance(time.Second)
_, relB, _ := m.Acquire(ctx, b)
relB()
clk.advance(time.Second)
_, relC, _ := m.Acquire(ctx, c) // over cap (3 > 2): evict the LRU unpinned, which is A
relC()
if m.Len() != 2 {
t.Fatalf("registry must stay at the cap, got %d", m.Len())
}
if fb.closeCount(a) != 1 {
t.Fatalf("the least recently used pool (A) must be closed on eviction, closes = %d", fb.closeCount(a))
}
if fb.closeCount(b) != 0 || fb.closeCount(c) != 0 {
t.Fatalf("B and C must remain open")
}
}
func TestPinnedPoolIsNeverEvicted(t *testing.T) {
a, b := uuid.New(), uuid.New()
fb := newFakeBuild()
m := newTestManager(1, mapLookup(map[uuid.UUID]directory.TenantConn{a: active(a), b: active(b)}), fb.build)
ctx := context.Background()
_, relA, _ := m.Acquire(ctx, a) // A pinned (not released)
_, relB, _ := m.Acquire(ctx, b) // over cap, but A is pinned so it cannot be evicted
if fb.closeCount(a) != 0 {
t.Fatalf("a pinned (in flight) pool must never be closed, A closes = %d", fb.closeCount(a))
}
if m.Len() != 2 {
t.Fatalf("registry is temporarily over cap with two pinned pools, got %d", m.Len())
}
relA()
relB()
}
func TestIdleSweepClosesQuietPools(t *testing.T) {
org := uuid.New()
fb := newFakeBuild()
clk := &clock{t: time.Unix(2000, 0)}
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{org: active(org)}), fb.build)
m.idle = 10 * time.Second
m.now = clk.now
_, rel, _ := m.Acquire(context.Background(), org)
rel()
clk.advance(11 * time.Second)
m.sweepOnce()
if m.Len() != 0 {
t.Fatalf("an idle pool past the TTL must be swept, live = %d", m.Len())
}
if fb.closeCount(org) != 1 {
t.Fatalf("a swept pool must be closed, closes = %d", fb.closeCount(org))
}
}
func TestCloseClosesAllAndRefuses(t *testing.T) {
a, b := uuid.New(), uuid.New()
fb := newFakeBuild()
m := newTestManager(8, mapLookup(map[uuid.UUID]directory.TenantConn{a: active(a), b: active(b)}), fb.build)
ctx := context.Background()
_, relA, _ := m.Acquire(ctx, a)
relA()
_, relB, _ := m.Acquire(ctx, b)
relB()
m.Close()
if fb.closeCount(a) != 1 || fb.closeCount(b) != 1 {
t.Fatalf("Close must close every live pool, A=%d B=%d", fb.closeCount(a), fb.closeCount(b))
}
if _, _, err := m.Acquire(ctx, a); !errors.Is(err, ErrClosed) {
t.Fatalf("a closed manager must refuse Acquire, got %v", err)
}
}