Skip to content

Commit 9452a1e

Browse files
myleshortonclaude
andcommitted
backend/unbounded: test PatchSettings dispatches UnboundedKey
A typo on the diff key (settings.UnboundedKey → settings.UnboundedKye) or a removal of the unbounded.Apply() call would silently leave the UI toggle persisted but inert. The peer-share side has TestPatchSettings_PeerShareDispatches catching exactly this class of regression; mirror it for Unbounded. unbounded/unbounded.go: - Add applyHook: a nil-in-production function pointer invoked at the top of Apply(), before any state check. Backend tests install a counter via SetApplyHookForTest to verify dispatch. This is the smallest possible test surface — exposing the manager's internals across packages just for the test wiring would be a much bigger surface, and the hook fires regardless of the Enabled() gate so tests catch dispatch even when no transition results. backend/radiance_test.go: - TestPatchSettings_UnboundedDispatches: install the hook, PATCH {UnboundedKey:true}, assert hook fired once; PATCH {UnboundedKey:false}, assert hook fired twice. Then PATCH {PeerShareEnabledKey:false} (a key OTHER than UnboundedKey) and assert the counter doesn't move — confirms the diff check is in place rather than always firing. Sanity-checked the test by removing the Apply call from PatchSettings: test fails with 'expected 2, actual 0'. Restored: test passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 991afac commit 9452a1e

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

backend/radiance_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/getlantern/radiance/common/settings"
1515
"github.com/getlantern/radiance/peer"
16+
"github.com/getlantern/radiance/unbounded"
1617
)
1718

1819
func TestBackend(t *testing.T) {}
@@ -216,3 +217,28 @@ func TestPatchSettings_PeerShareDispatches(t *testing.T) {
216217
assert.Equal(t, int64(1), fake.stopCalls.Load())
217218
assert.False(t, fake.IsActive())
218219
}
220+
221+
// Verify PatchSettings routes UnboundedKey to unbounded.Apply via the
222+
// SetApplyHookForTest hook. Companion to TestPatchSettings_PeerShareDispatches —
223+
// a typo on the diff key or a removal of the Apply call would silently
224+
// leave the Unbounded toggle persisted but inert. The hook fires
225+
// regardless of the Enabled() gate inside Apply, so this catches the
226+
// dispatch even though we don't prime the rest of the manager state.
227+
func TestPatchSettings_UnboundedDispatches(t *testing.T) {
228+
r := newPeerTestBackend(t, &fakePeerController{})
229+
230+
var applyCalls atomic.Int32
231+
unbounded.SetApplyHookForTest(func() { applyCalls.Add(1) })
232+
t.Cleanup(func() { unbounded.SetApplyHookForTest(nil) })
233+
234+
require.NoError(t, r.PatchSettings(settings.Settings{settings.UnboundedKey: true}))
235+
assert.Equal(t, int32(1), applyCalls.Load(), "PatchSettings({UnboundedKey: true}) must dispatch to unbounded.Apply")
236+
237+
require.NoError(t, r.PatchSettings(settings.Settings{settings.UnboundedKey: false}))
238+
assert.Equal(t, int32(2), applyCalls.Load(), "PatchSettings({UnboundedKey: false}) must dispatch to unbounded.Apply")
239+
240+
// A PATCH without UnboundedKey must NOT trigger Apply — confirms
241+
// the diff check is in place rather than always firing.
242+
require.NoError(t, r.PatchSettings(settings.Settings{settings.PeerShareEnabledKey: false}))
243+
assert.Equal(t, int32(2), applyCalls.Load(), "PatchSettings without UnboundedKey must not dispatch to unbounded.Apply")
244+
}

unbounded/unbounded.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ func SetEnabled(enable bool) error {
200200
// armed gate is also checked inside start, so even a queued
201201
// transition stays a no-op after Stop.
202202
func Apply() error {
203+
if h := applyHook; h != nil {
204+
h()
205+
}
203206
if !Enabled() {
204207
manager.stop()
205208
return nil
@@ -337,6 +340,23 @@ func Stop(ctx context.Context) error {
337340
// applies for the duration of the test.
338341
var internalStopTimeout = 5 * time.Second
339342

343+
// applyHook is invoked at the top of Apply, before any state check
344+
// or transition. nil in production; backend tests install a counter
345+
// or assertion to verify that PatchSettings actually dispatches the
346+
// UnboundedKey diff to this package. Keep this minimal — exposing
347+
// the manager's internals across packages just for test wiring
348+
// would be a much bigger surface.
349+
var applyHook func()
350+
351+
// SetApplyHookForTest installs h to be invoked at the start of
352+
// every Apply call. Pass nil to remove. Test-only; production code
353+
// must not call this. The hook fires regardless of the Enabled()
354+
// gate so callers can verify dispatch happened even when no
355+
// transition results.
356+
func SetApplyHookForTest(h func()) {
357+
applyHook = h
358+
}
359+
340360
// stopCtx is the shared implementation for both the public Stop
341361
// (disarm=true) and internal manager.stop (disarm=false). Holds
342362
// transitionMu for the entire signal+wait so a concurrent start

0 commit comments

Comments
 (0)