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) } }