Files
nmon/internal/groups/rig_test.go

99 lines
2.8 KiB
Go

package groups
import (
"context"
"strconv"
"testing"
"time"
"github.com/v10networks/nmon/internal/clock"
"github.com/v10networks/nmon/internal/p95"
"github.com/v10networks/nmon/internal/p95/p95test"
"github.com/v10networks/nmon/internal/store"
"github.com/v10networks/nmon/internal/testutil"
"github.com/v10networks/nmon/internal/ulid"
)
var toronto = func() *time.Location {
l, err := time.LoadLocation("America/Toronto")
if err != nil {
panic(err)
}
return l
}()
// rig is a real SQLite inventory, a fake long store and a fake clock.
type rig struct {
st store.Store
clk *clock.Fake
long *p95test.Long
alarms *p95test.Alarms
dev *store.Device
group store.Group
opts Options
}
func newRig(t *testing.T) *rig { return newRigAt(t, time.Date(2026, 5, 3, 0, 0, 0, 0, time.UTC)) }
func newRigAt(t *testing.T, now time.Time) *rig {
t.Helper()
clk := clock.NewFake(now)
st := testutil.OpenStore(t, clk)
dev := &store.Device{Name: "sw1", Kind: store.KindNetwork, Enabled: true}
must(t, st.CreateDevice(context.Background(), dev))
g := store.Group{Name: "Acme", Kind: store.GroupCustomer}
must(t, st.CreateGroup(context.Background(), &g))
long := p95test.NewLong()
r := &rig{st: st, clk: clk, long: long, alarms: &p95test.Alarms{}, dev: dev, group: g}
r.opts = Options{Query: long, Inventory: st, Zone: toronto, Clock: clk}
return r
}
func must(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
func (r *rig) svc() *Service { return NewService(r.opts) }
var ifaceSeq int64
func (r *rig) iface(t *testing.T, unreliable bool) string {
t.Helper()
ifaceSeq++
i := store.Interface{ID: ulid.New(r.clk.Now()), DeviceID: r.dev.ID, IfIndex: ifaceSeq, IfName: "e" + strconv.FormatInt(ifaceSeq, 10),
AdminStatus: 1, OperStatus: 1, HasHCCounters: !unreliable, Unreliable: unreliable}
must(t, r.st.UpsertInterfaces(context.Background(), r.dev.ID, []store.Interface{i}))
return i.ID
}
// member adds an open membership starting at from.
func (r *rig) member(t *testing.T, id, dir string, from time.Time) {
t.Helper()
must(t, r.st.AddGroupMember(context.Background(), store.GroupMember{
GroupID: r.group.ID, InterfaceID: id, Direction: dir, EffectiveFrom: from}))
}
// rates sets in/out for every window in [from, to); fn returns the pair for window i.
func (r *rig) rates(id string, from, to time.Time, fn func(i int) (in, out float64, ok bool)) {
for i, ts := 0, from; ts.Before(to); i, ts = i+1, ts.Add(p95.Window) {
if in, out, ok := fn(i); ok {
r.long.Set(id, p95.DirIn, ts, in)
r.long.Set(id, p95.DirOut, ts, out)
}
}
}
func constant(in, out float64) func(int) (float64, float64, bool) {
return func(int) (float64, float64, bool) { return in, out, true }
}
func month(t *testing.T, label string) p95.Month {
t.Helper()
m, err := p95.ParseMonth(label, toronto)
must(t, err)
return m
}