stability_test.go raw
1 package oracle
2
3 import "testing"
4
5 func TestStabilityMonitorTriggersOnOscillation(t *testing.T) {
6 sm := NewStabilityMonitor(5, 3)
7
8 // Feed rising bond rate — no trigger yet.
9 for i := range 5 {
10 if sm.Observe(100, int64(20+i*10), uint32(i)) {
11 t.Fatalf("unexpected trigger at observation %d (rising phase)", i)
12 }
13 }
14
15 // Now oscillate: feed alternating high/low to trigger reversals.
16 gen := uint32(5)
17 triggered := false
18 for round := range 20 {
19 var bonded int64
20 if round%2 == 0 {
21 bonded = 20 // low
22 } else {
23 bonded = 80 // high
24 }
25 if sm.Observe(100, bonded, gen) {
26 triggered = true
27 break
28 }
29 gen++
30 }
31
32 if !triggered {
33 t.Fatal("stability monitor did not trigger after oscillation")
34 }
35
36 if sm.LastSignalGen == 0 {
37 t.Error("LastSignalGen not updated")
38 }
39 }
40
41 func TestStabilityMonitorResetsAfterTrigger(t *testing.T) {
42 sm := NewStabilityMonitor(3, 3)
43
44 // Force oscillation.
45 gen := uint32(0)
46 for range 30 {
47 bonded := int64(80)
48 if gen%2 == 0 {
49 bonded = 20
50 }
51 if sm.Observe(100, bonded, gen) {
52 break
53 }
54 gen++
55 }
56
57 // After trigger, detector should be reset — reversals back to 0.
58 if sm.Detector.Reversals != 0 {
59 t.Errorf("reversals not reset after trigger: %d", sm.Detector.Reversals)
60 }
61
62 // Should not immediately re-trigger on next observation.
63 if sm.Observe(100, 50, gen+1) {
64 t.Error("re-triggered immediately after reset")
65 }
66 }
67
68 func TestStabilityMonitorSteadyStateNoTrigger(t *testing.T) {
69 sm := NewStabilityMonitor(5, 3)
70
71 // Feed steady rising bond rate — should never trigger.
72 for i := range 50 {
73 if sm.Observe(100, int64(10+i), uint32(i)) {
74 t.Fatalf("triggered on steadily rising input at observation %d", i)
75 }
76 }
77 }
78