fix(bandopen): the watch switch now gates the detector
"Watch for band openings" only ever governed the extra DATA SOURCES — the RBN nodes and the PSK Reporter feed. The detector itself ran on every ordinary cluster spot regardless, so an operator who had never enabled the watch still got 10 m and 6 m opening banners from a feature he had deliberately left off. The flag is cached on bandOpenState rather than read per spot: this is the cluster hot path, where a settings query per spot is exactly what the rest of this file avoids. startBandOpenFeed owns it, and it already runs at startup and on every save, so the switch takes effect without a restart. Switching it off also clears the live badges and the accumulated spot window. The badges only fade on a timer fed by spots the detector no longer looks at, so they would otherwise hang there until the next restart; and dropping the window means switching back on starts from what is on the air rather than from an hour-old burst. The remembered openings are kept — those really happened.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"hamlog/internal/bandopen"
|
||||
"hamlog/internal/cluster"
|
||||
)
|
||||
|
||||
// The "Watch for band openings" switch has to gate the DETECTOR, not just the
|
||||
// extra data sources.
|
||||
//
|
||||
// It originally governed only the RBN nodes and the PSK Reporter feed, while
|
||||
// the detector itself ran on every ordinary cluster spot — so an operator who
|
||||
// had never enabled the watch still got opening banners for a feature he had
|
||||
// deliberately left off. That is what this pins.
|
||||
func TestBandOpenWatchGatesTheDetector(t *testing.T) {
|
||||
spot := func() cluster.Spot {
|
||||
return cluster.Spot{
|
||||
DXCall: "EA1ABC", Band: "6m", DistanceKm: 1400, ShortPath: 210,
|
||||
ReceivedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Switched off: the spot must not even reach the detector.
|
||||
off := &App{opSet: true, opLat: 48.0, opLon: 2.0}
|
||||
off.detectBandOpening(spot())
|
||||
if off.bandOpen.det != nil {
|
||||
t.Error("the detector ran with the watch switched off")
|
||||
}
|
||||
|
||||
// Switched on: the same spot is accepted (one spot is not an opening, so
|
||||
// nothing is announced — but the detector now exists and is collecting).
|
||||
on := &App{opSet: true, opLat: 48.0, opLon: 2.0}
|
||||
on.bandOpen.on.Store(true)
|
||||
on.detectBandOpening(spot())
|
||||
if on.bandOpen.det == nil {
|
||||
t.Error("the detector did not run with the watch switched on")
|
||||
}
|
||||
}
|
||||
|
||||
// Switching the watch off must put the badges out. They fade on a timer fed by
|
||||
// spots the detector no longer looks at, so left alone they would stay lit
|
||||
// until the next restart.
|
||||
func TestClearBandOpeningsPutsTheBadgesOut(t *testing.T) {
|
||||
a := &App{}
|
||||
a.bandOpen.live = map[string]bandopen.Opening{"6m": {Band: "6m", Calls: 9}}
|
||||
a.bandOpen.aliveUntil = map[string]time.Time{"6m": time.Now().Add(time.Hour)}
|
||||
a.bandOpen.det = bandopen.New(bandopen.DefaultConfig())
|
||||
a.bandOpen.last = []bandopen.Opening{{Band: "6m", Calls: 9}}
|
||||
|
||||
a.clearBandOpenings()
|
||||
|
||||
if got := a.GetLiveOpenings(); len(got) != 0 {
|
||||
t.Errorf("a badge stayed lit after the watch was switched off: %v", got)
|
||||
}
|
||||
if a.bandOpen.det != nil {
|
||||
t.Error("the accumulated spot window survived — switching back on would start from a stale burst")
|
||||
}
|
||||
// The history is NOT cleared: those openings really happened.
|
||||
if len(a.GetBandOpenings()) != 1 {
|
||||
t.Error("the remembered openings were thrown away")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user