100 lines
3.3 KiB
Go
100 lines
3.3 KiB
Go
//go:build integration
|
|
|
|
package inventory
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// **The durations the bounds are set from are recorded once each** (novox/hq to-be 45 Phase 0): a
|
|
// send measured at its first report and not again at every reconcile that repeats it; a send of
|
|
// something else measures nothing; a new send is a new measurement.
|
|
func TestAnApplyIsMeasuredOncePerSend(t *testing.T) {
|
|
inv := ForTest(t)
|
|
ctx := t.Context()
|
|
node, err := inv.AddNode(ctx, "anchor")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.RecordSent(ctx, node.ID, "d1", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for range 3 { // the report, then two reconciles saying the same
|
|
if err := inv.RecordApplyDuration(ctx, "anchor", "d1", OutcomeApplied); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := inv.RecordApplyDuration(ctx, "anchor", "d0", OutcomeApplied); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ds, err := inv.Durations(ctx, DurationApply, time.Now().Add(-time.Hour))
|
|
if err != nil || len(ds) != 1 || ds[0].Subject != "anchor" || ds[0].Detail != OutcomeApplied || ds[0].Took < 0 {
|
|
t.Fatalf("%v %+v", err, ds)
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
if err := inv.RecordSent(ctx, node.ID, "d2", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.RecordApplyDuration(ctx, "anchor", "d2", OutcomeFailed); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ds, _ = inv.Durations(ctx, "", time.Now().Add(-time.Hour)); len(ds) != 2 {
|
|
t.Fatalf("a second send was not measured: %+v", ds)
|
|
}
|
|
}
|
|
|
|
// A machine's silence is the time since its last word, once per word.
|
|
func TestASilenceIsMeasuredFromTheLastWord(t *testing.T) {
|
|
inv := ForTest(t)
|
|
ctx := t.Context()
|
|
before := time.Now().Add(-90 * time.Second)
|
|
for range 2 {
|
|
if err := inv.RecordHeartbeatGap(ctx, "anchor", before); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := inv.RecordHeartbeatGap(ctx, "anchor", time.Time{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ds, err := inv.Durations(ctx, DurationHeartbeatGap, time.Now().Add(-time.Hour))
|
|
if err != nil || len(ds) != 1 || ds[0].Took < 90*time.Second || ds[0].Took > 2*time.Minute {
|
|
t.Fatalf("%v %+v", err, ds)
|
|
}
|
|
}
|
|
|
|
// A plan's tier is measured when the plan leaves it — moving on, or ending — and only then.
|
|
func TestAPlansTierIsMeasuredWhenItIsLeft(t *testing.T) {
|
|
inv := ForTest(t)
|
|
ctx := t.Context()
|
|
p := Plan{ID: "plan-1", Repository: "novox/mesh-tools", Commit: "abc", Created: time.Now().UTC(),
|
|
State: PlanBuilding, Tiers: [][]string{{"mesh-tools"}, {"builder"}},
|
|
Modules: map[string]*PlanModule{"mesh-tools": {}, "builder": {}}}
|
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p.State = PlanRolling // the same tier, saved again
|
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ds, _ := inv.Durations(ctx, DurationPlanTier, time.Now().Add(-time.Hour)); len(ds) != 0 {
|
|
t.Fatalf("a tier not left was measured: %+v", ds)
|
|
}
|
|
p.Tier = 1
|
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p.State = PlanDone
|
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.SavePlan(ctx, &p); err != nil { // saved again once ended: nothing more to measure
|
|
t.Fatal(err)
|
|
}
|
|
ds, err := inv.Durations(ctx, DurationPlanTier, time.Now().Add(-time.Hour))
|
|
if err != nil || len(ds) != 2 || ds[0].Subject != "novox/mesh-tools" || ds[0].Ref != "plan-1/tier-0" ||
|
|
ds[1].Ref != "plan-1/tier-1" {
|
|
t.Fatalf("%v %+v", err, ds)
|
|
}
|
|
}
|