Synchronize auto-compact setting updates
- commit
- 4a6e7a5798972a35878c17aa7280740c5c7bb318
- author
- patriceckhart · · 2026-07-28 11:49 UTC
- parent
- d24acdc
- signature
- unsigned
2 files · +60 -1
M packages/agent/modes/auto_compact_test.go +59 -0
| @@ -85,6 +85,65 @@ func TestSettingsDialogOffersAutoCompactThresholdPresets(t *testing.T) { | |||
| 85 | 85 | } | |
| 86 | 86 | } | |
| 87 | 87 | ||
| 88 | + | func TestApplyAutoCompactThresholdSynchronizesLiveUpdate(t *testing.T) { | |
| 89 | + | initialThreshold := 85 | |
| 90 | + | releaseStore := make(chan struct{}) | |
| 91 | + | store := &blockingAutoCompactSettingsStore{ | |
| 92 | + | entered: make(chan int, 1), | |
| 93 | + | release: releaseStore, | |
| 94 | + | } | |
| 95 | + | interactive := NewInteractive(InteractiveConfig{ | |
| 96 | + | AutoCompactThreshold: &initialThreshold, | |
| 97 | + | SettingsStore: store, | |
| 98 | + | }) | |
| 99 | + | ||
| 100 | + | interactive.mu.Lock() | |
| 101 | + | locked := true | |
| 102 | + | released := false | |
| 103 | + | done := make(chan struct{}) | |
| 104 | + | go func() { | |
| 105 | + | defer close(done) | |
| 106 | + | interactive.applyAutoCompactThresholdSetting("70") | |
| 107 | + | }() | |
| 108 | + | defer func() { | |
| 109 | + | if !released { | |
| 110 | + | close(releaseStore) | |
| 111 | + | } | |
| 112 | + | if locked { | |
| 113 | + | interactive.mu.Unlock() | |
| 114 | + | } | |
| 115 | + | <-done | |
| 116 | + | }() | |
| 117 | + | ||
| 118 | + | if got := <-store.entered; got != 70 { | |
| 119 | + | t.Fatalf("persisted threshold = %d, want 70", got) | |
| 120 | + | } | |
| 121 | + | if got := *interactive.cfg.AutoCompactThreshold; got != 85 { | |
| 122 | + | t.Fatalf("threshold changed without holding Interactive.mu: got %d, want 85", got) | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | close(releaseStore) | |
| 126 | + | released = true | |
| 127 | + | interactive.mu.Unlock() | |
| 128 | + | locked = false | |
| 129 | + | <-done | |
| 130 | + | if got := *interactive.cfg.AutoCompactThreshold; got != 70 { | |
| 131 | + | t.Fatalf("threshold after setting completes = %d, want 70", got) | |
| 132 | + | } | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | type blockingAutoCompactSettingsStore struct { | |
| 136 | + | SettingsStore | |
| 137 | + | entered chan int | |
| 138 | + | release <-chan struct{} | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | func (s *blockingAutoCompactSettingsStore) SetAutoCompactThreshold(percent int) error { | |
| 142 | + | s.entered <- percent | |
| 143 | + | <-s.release | |
| 144 | + | return nil | |
| 145 | + | } | |
| 146 | + | ||
| 88 | 147 | func autoCompactIntPtr(value int) *int { | |
| 89 | 148 | return &value | |
| 90 | 149 | } | |
| @@ -85,6 +85,65 @@ func TestSettingsDialogOffersAutoCompactThresholdPresets(t *testing.T) { | |||||
| 85 | } | 85 | } | ||
| 86 | } | 86 | } | ||
| 87 | 87 | ||||
| 88 | + | func TestApplyAutoCompactThresholdSynchronizesLiveUpdate(t *testing.T) { | |||
| 89 | + | initialThreshold := 85 | |||
| 90 | + | releaseStore := make(chan struct{}) | |||
| 91 | + | store := &blockingAutoCompactSettingsStore{ | |||
| 92 | + | entered: make(chan int, 1), | |||
| 93 | + | release: releaseStore, | |||
| 94 | + | } | |||
| 95 | + | interactive := NewInteractive(InteractiveConfig{ | |||
| 96 | + | AutoCompactThreshold: &initialThreshold, | |||
| 97 | + | SettingsStore: store, | |||
| 98 | + | }) | |||
| 99 | + | ||||
| 100 | + | interactive.mu.Lock() | |||
| 101 | + | locked := true | |||
| 102 | + | released := false | |||
| 103 | + | done := make(chan struct{}) | |||
| 104 | + | go func() { | |||
| 105 | + | defer close(done) | |||
| 106 | + | interactive.applyAutoCompactThresholdSetting("70") | |||
| 107 | + | }() | |||
| 108 | + | defer func() { | |||
| 109 | + | if !released { | |||
| 110 | + | close(releaseStore) | |||
| 111 | + | } | |||
| 112 | + | if locked { | |||
| 113 | + | interactive.mu.Unlock() | |||
| 114 | + | } | |||
| 115 | + | <-done | |||
| 116 | + | }() | |||
| 117 | + | ||||
| 118 | + | if got := <-store.entered; got != 70 { | |||
| 119 | + | t.Fatalf("persisted threshold = %d, want 70", got) | |||
| 120 | + | } | |||
| 121 | + | if got := *interactive.cfg.AutoCompactThreshold; got != 85 { | |||
| 122 | + | t.Fatalf("threshold changed without holding Interactive.mu: got %d, want 85", got) | |||
| 123 | + | } | |||
| 124 | + | ||||
| 125 | + | close(releaseStore) | |||
| 126 | + | released = true | |||
| 127 | + | interactive.mu.Unlock() | |||
| 128 | + | locked = false | |||
| 129 | + | <-done | |||
| 130 | + | if got := *interactive.cfg.AutoCompactThreshold; got != 70 { | |||
| 131 | + | t.Fatalf("threshold after setting completes = %d, want 70", got) | |||
| 132 | + | } | |||
| 133 | + | } | |||
| 134 | + | ||||
| 135 | + | type blockingAutoCompactSettingsStore struct { | |||
| 136 | + | SettingsStore | |||
| 137 | + | entered chan int | |||
| 138 | + | release <-chan struct{} | |||
| 139 | + | } | |||
| 140 | + | ||||
| 141 | + | func (s *blockingAutoCompactSettingsStore) SetAutoCompactThreshold(percent int) error { | |||
| 142 | + | s.entered <- percent | |||
| 143 | + | <-s.release | |||
| 144 | + | return nil | |||
| 145 | + | } | |||
| 146 | + | ||||
| 88 | func autoCompactIntPtr(value int) *int { | 147 | func autoCompactIntPtr(value int) *int { | ||
| 89 | return &value | 148 | return &value | ||
| 90 | } | 149 | } | ||
M packages/agent/modes/interactive.go +1 -1
| @@ -3395,7 +3395,6 @@ func (i *Interactive) applyAutoCompactThresholdSetting(value string) { | |||
| 3395 | 3395 | return | |
| 3396 | 3396 | } | |
| 3397 | 3397 | threshold = normalizeAutoCompactThreshold(&threshold) | |
| 3398 | - | i.cfg.AutoCompactThreshold = &threshold | |
| 3399 | 3398 | if store, ok := i.cfg.SettingsStore.(autoCompactThresholdSettingsStore); ok { | |
| 3400 | 3399 | if err := store.SetAutoCompactThreshold(threshold); err != nil { | |
| 3401 | 3400 | i.mu.Lock() | |
| @@ -3405,6 +3404,7 @@ func (i *Interactive) applyAutoCompactThresholdSetting(value string) { | |||
| 3405 | 3404 | } | |
| 3406 | 3405 | } | |
| 3407 | 3406 | i.mu.Lock() | |
| 3407 | + | i.cfg.AutoCompactThreshold = &threshold | |
| 3408 | 3408 | if threshold == 0 { | |
| 3409 | 3409 | i.statusOK = "auto-compact threshold off" | |
| 3410 | 3410 | } else { | |
| @@ -3395,7 +3395,6 @@ func (i *Interactive) applyAutoCompactThresholdSetting(value string) { | |||||
| 3395 | return | 3395 | return | ||
| 3396 | } | 3396 | } | ||
| 3397 | threshold = normalizeAutoCompactThreshold(&threshold) | 3397 | threshold = normalizeAutoCompactThreshold(&threshold) | ||
| 3398 | - | i.cfg.AutoCompactThreshold = &threshold | |||
| 3399 | if store, ok := i.cfg.SettingsStore.(autoCompactThresholdSettingsStore); ok { | 3398 | if store, ok := i.cfg.SettingsStore.(autoCompactThresholdSettingsStore); ok { | ||
| 3400 | if err := store.SetAutoCompactThreshold(threshold); err != nil { | 3399 | if err := store.SetAutoCompactThreshold(threshold); err != nil { | ||
| 3401 | i.mu.Lock() | 3400 | i.mu.Lock() | ||
| @@ -3405,6 +3404,7 @@ func (i *Interactive) applyAutoCompactThresholdSetting(value string) { | |||||
| 3405 | } | 3404 | } | ||
| 3406 | } | 3405 | } | ||
| 3407 | i.mu.Lock() | 3406 | i.mu.Lock() | ||
| 3407 | + | i.cfg.AutoCompactThreshold = &threshold | |||
| 3408 | if threshold == 0 { | 3408 | if threshold == 0 { | ||
| 3409 | i.statusOK = "auto-compact threshold off" | 3409 | i.statusOK = "auto-compact threshold off" | ||
| 3410 | } else { | 3410 | } else { | ||