141 lines
3.3 KiB
Go
141 lines
3.3 KiB
Go
package talkgroups_test
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
"dynatron.me/x/stillbox/internal/ruletime"
|
|
"dynatron.me/x/stillbox/internal/trending"
|
|
"dynatron.me/x/stillbox/pkg/talkgroups"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAlertConfig(t *testing.T) {
|
|
ac := make(talkgroups.AlertConfig)
|
|
parseTests := []struct {
|
|
name string
|
|
tg talkgroups.ID
|
|
conf string
|
|
compare []talkgroups.AlertRule
|
|
expectErr error
|
|
}{
|
|
{
|
|
name: "base case",
|
|
tg: talkgroups.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: []talkgroups.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: talkgroups.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 talkgroups.ID
|
|
t time.Time
|
|
origScore float64
|
|
expectScore float64
|
|
}{
|
|
{
|
|
name: "base eval",
|
|
tg: talkgroups.TG(197, 3),
|
|
t: tMust("1:20"),
|
|
origScore: 3,
|
|
expectScore: 0.6,
|
|
},
|
|
{
|
|
name: "base eval",
|
|
tg: talkgroups.TG(197, 3),
|
|
t: tMust("23:03"),
|
|
origScore: 3,
|
|
expectScore: 3,
|
|
},
|
|
{
|
|
name: "base eval",
|
|
tg: talkgroups.TG(197, 3),
|
|
t: tMust("8:03"),
|
|
origScore: 1.0,
|
|
expectScore: 0.2,
|
|
},
|
|
{
|
|
name: "base eval",
|
|
tg: talkgroups.TG(197, 3),
|
|
t: tMust("15:15"),
|
|
origScore: 3.0,
|
|
expectScore: 6.0,
|
|
},
|
|
{
|
|
name: "overlapping eval",
|
|
tg: talkgroups.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[talkgroups.ID]{
|
|
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
|
|
}
|