stillbox/pkg/calls/alertconfig_test.go

141 lines
3.2 KiB
Go

package calls_test
import (
"errors"
"math"
"testing"
"time"
"dynatron.me/x/stillbox/internal/ruletime"
"dynatron.me/x/stillbox/internal/trending"
"dynatron.me/x/stillbox/pkg/calls"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAlertConfig(t *testing.T) {
ac := make(calls.AlertConfig)
parseTests := []struct {
name string
tg calls.Talkgroup
conf string
compare []calls.AlertRule
expectErr error
}{
{
name: "base case",
tg: calls.TG(197, 3),
conf: `[{"times":["7:00+2h","01:00+1h","16:00+1h","19:00+4h"],"mult":0.2},{"times":["11:00+1h","15:00+30m","16:03+20m"],"mult":2.0}]`,
compare: []calls.AlertRule{
{
Times: []ruletime.RuleTime{
ruletime.Must(ruletime.New("7:00+2h")),
ruletime.Must(ruletime.New("1:00+1h")),
ruletime.Must(ruletime.New("16:00+1h")),
ruletime.Must(ruletime.New("19:00+4h")),
},
ScoreMultiplier: 0.2,
},
{
Times: []ruletime.RuleTime{
ruletime.Must(ruletime.New("11:00+1h")),
ruletime.Must(ruletime.New("15:00+30m")),
ruletime.Must(ruletime.New("16:03+20m")),
},
ScoreMultiplier: 2.0,
},
},
},
{
name: "bad spec",
tg: calls.TG(197, 3),
conf: `[{"times":["26:00+2h","01:00+1h","19:00+4h"],"mult":0.2},{"times":["11:00+1h","15:00+30m"],"mult":2.0}]`,
expectErr: errors.New("'26:00+2h': invalid hours"),
},
}
for _, tc := range parseTests {
t.Run(tc.name, func(t *testing.T) {
err := ac.AddAlertConfig(tc.tg, []byte(tc.conf))
if tc.expectErr != nil {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.expectErr.Error())
} else {
assert.Equal(t, tc.compare, ac[tc.tg])
}
})
}
tMust := func(s string) time.Time {
t, err := time.ParseInLocation("2006-01-02 15:04", "2024-11-02 "+s, time.Local)
if err != nil {
panic(err)
}
return t
}
evalTests := []struct {
name string
tg calls.Talkgroup
t time.Time
origScore float64
expectScore float64
}{
{
name: "base eval",
tg: calls.TG(197, 3),
t: tMust("1:20"),
origScore: 3,
expectScore: 0.6,
},
{
name: "base eval",
tg: calls.TG(197, 3),
t: tMust("23:03"),
origScore: 3,
expectScore: 3,
},
{
name: "base eval",
tg: calls.TG(197, 3),
t: tMust("8:03"),
origScore: 1.0,
expectScore: 0.2,
},
{
name: "base eval",
tg: calls.TG(197, 3),
t: tMust("15:15"),
origScore: 3.0,
expectScore: 6.0,
},
{
name: "overlapping eval",
tg: calls.TG(197, 3),
t: tMust("16:10"),
origScore: 1.0,
expectScore: 0.4,
},
}
for _, tc := range evalTests {
t.Run(tc.name, func(t *testing.T) {
cs := trending.Score[calls.Talkgroup]{
ID: tc.tg,
Score: tc.origScore,
}
assert.Equal(t, tc.expectScore, toFixed(ac.ApplyAlertRules(cs, tc.t), 5))
})
}
}
func round(num float64) int {
return int(num + math.Copysign(0.5, num))
}
func toFixed(num float64, precision int) float64 {
output := math.Pow(10, float64(precision))
return float64(round(num*output)) / output
}