The chips in Settings only ever shaped the PSK Reporter SUBSCRIPTION. Neither feed path checked them: both asked bandopen.Watched, which says which bands the detector is capable of and knows nothing about the selection. So the cluster path announced every watched band regardless, and widening the subscription to "+" for grid chasing let PSK Reporter do the same — a station with only 6 m ticked got 10 m and 2 m badges. The selection is now cached beside the on/off flag and checked on both paths, and unticking a band puts its badge out: badges fade on a timer fed by spots the detector no longer looks at, so it would otherwise stay lit until a restart.
119 lines
4.0 KiB
Go
119 lines
4.0 KiB
Go
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")
|
|
}
|
|
}
|
|
|
|
// Unticking a band in Settings must actually stop its announcements.
|
|
//
|
|
// Nothing checked the operator's selection on either feed path: bandopen.Watched
|
|
// only says which bands the detector is CAPABLE of. So a station with just 6 m
|
|
// ticked still got 10 m and 2 m badges, from the cluster path and — once grid
|
|
// chasing widened the subscription to every band — from PSK Reporter too.
|
|
func TestBandOpenHonoursTheSelectedBands(t *testing.T) {
|
|
a := &App{opSet: true, opLat: 48, opLon: 2}
|
|
a.bandOpen.on.Store(true)
|
|
a.setBandOpenBands([]string{"6m"})
|
|
|
|
if !a.bandOpenWanted("6m") {
|
|
t.Error("6m is ticked and was refused")
|
|
}
|
|
for _, b := range []string{"10m", "2m", "4m"} {
|
|
if a.bandOpenWanted(b) {
|
|
t.Errorf("%s is not ticked and was accepted", b)
|
|
}
|
|
}
|
|
// A band the detector cannot watch at all stays out whatever is stored.
|
|
if a.bandOpenWanted("20m") {
|
|
t.Error("20m is not a watched band and was accepted")
|
|
}
|
|
|
|
// And the cluster path must obey it too.
|
|
a.detectBandOpening(cluster.Spot{
|
|
DXCall: "K1ABC", Band: "10m", DistanceKm: 6000, ShortPath: 280, ReceivedAt: time.Now(),
|
|
})
|
|
if a.bandOpen.det != nil {
|
|
t.Error("a spot on an unticked band reached the detector")
|
|
}
|
|
}
|
|
|
|
// Unticking a band puts its badge out. They fade on a timer fed by spots the
|
|
// detector no longer looks at, so it would otherwise stay lit until a restart.
|
|
func TestUntickingABandClearsItsBadge(t *testing.T) {
|
|
a := &App{}
|
|
a.bandOpen.live = map[string]bandopen.Opening{
|
|
"6m": {Band: "6m", Calls: 9},
|
|
"10m": {Band: "10m", Calls: 5},
|
|
}
|
|
a.bandOpen.aliveUntil = map[string]time.Time{
|
|
"6m": time.Now().Add(time.Hour),
|
|
"10m": time.Now().Add(time.Hour),
|
|
}
|
|
a.setBandOpenBands([]string{"6m"})
|
|
|
|
live := a.GetLiveOpenings()
|
|
if len(live) != 1 || live[0].Band != "6m" {
|
|
t.Errorf("live openings = %v, want only 6m", live)
|
|
}
|
|
}
|