| 1 | package evidence |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | func drainRunwayShadow(r *runwayShadow, sample OutcomeSample) int { |
| 6 | for round := 1; round <= 100; round++ { |
| 7 | if r.observe(sample).spent { |
| 8 | return round |
| 9 | } |
| 10 | } |
| 11 | return -1 |
| 12 | } |
| 13 | |
| 14 | func TestRunwayShadowPricesOutcomesWithoutAFixedRoundCliff(t *testing.T) { |
| 15 | var repeating runwayShadow |
| 16 | if got := drainRunwayShadow(&repeating, OutcomeSample{}); got != runwayStartBalance/runwayRoundCost { |
| 17 | t.Errorf("empty rounds lasted %d, want %d", got, runwayStartBalance/runwayRoundCost) |
| 18 | } |
| 19 | |
| 20 | var exploring runwayShadow |
| 21 | if got := drainRunwayShadow(&exploring, OutcomeSample{Exploration: 1}); got != runwayStartBalance { |
| 22 | t.Errorf("exploration rounds lasted %d, want %d", got, runwayStartBalance) |
| 23 | } |
| 24 | |
| 25 | for name, sample := range map[string]OutcomeSample{ |
| 26 | "changing": {Churn: 1}, |
| 27 | "checking": {Discriminating: 1}, |
| 28 | } { |
| 29 | var productive runwayShadow |
| 30 | if got := drainRunwayShadow(&productive, sample); got != -1 { |
| 31 | t.Errorf("%s account spent after %d rounds", name, got) |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | func TestRunwayShadowIsBoundedAndSeparatesDryFromIdle(t *testing.T) { |
| 37 | var r runwayShadow |
| 38 | for range 100 { |
| 39 | r.observe(OutcomeSample{Discriminating: 1}) |
| 40 | } |
| 41 | if got := drainRunwayShadow(&r, OutcomeSample{Exploration: 1}); got != runwayMaxBalance { |
| 42 | t.Errorf("banked account lasted %d exploration rounds, want %d", got, runwayMaxBalance) |
| 43 | } |
| 44 | |
| 45 | var counts runwayShadow |
| 46 | for range 3 { |
| 47 | counts.observe(OutcomeSample{Exploration: 1}) |
| 48 | } |
| 49 | state := counts.observe(OutcomeSample{}) |
| 50 | if state.idle != 4 || state.dry != 1 { |
| 51 | t.Fatalf("quiet round state = %+v, want idle 4 dry 1", state) |
| 52 | } |
| 53 | state = counts.observe(OutcomeSample{Churn: 1}) |
| 54 | if state.idle != 0 || state.dry != 0 { |
| 55 | t.Fatalf("change state = %+v, want cleared counters", state) |
| 56 | } |
| 57 | } |
| 58 |