carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package activator
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "github.com/carlosframework/platform/internal/registry"
9)
10
11// The plans idle hook (plans 2): a plan may only shorten an entry's idle
12// window, never lengthen it, and never touches an always-on worker.
13
14func idleFor(d time.Duration) func(registry.Route) time.Duration {
15 return func(registry.Route) time.Duration { return d }
16}
17
18func wakeInstance(t *testing.T, a *Service, host string) {
19 t.Helper()
20 release, err := a.beginRequest(context.Background(), testRoute(host))
21 if err != nil {
22 t.Fatalf("beginRequest: %v", err)
23 }
24 release()
25}
26
27func TestIdleForShortensAnInstance(t *testing.T) {
28 t.Parallel()
29 a, _, clk, _ := testActivator(t, 15*time.Minute)
30 a.SetIdleFor(idleFor(90 * time.Second))
31 wakeInstance(t, a, "one.example.com")
32 clk.advance(80 * time.Second)
33 a.sweepOnce()
34 if a.entryCount() != 1 {
35 t.Fatal("slept before the plan's 90s window")
36 }
37 clk.advance(11 * time.Second)
38 a.sweepOnce()
39 waitFor(t, "plan idle sleep", func() bool { return a.entryCount() == 0 })
40}
41
42func TestPlanIdleOnlyShortens(t *testing.T) {
43 t.Parallel()
44 a, _, clk, _ := testActivator(t, 5*time.Minute)
45 a.SetIdleFor(idleFor(15 * time.Minute))
46 wakeInstance(t, a, "one.example.com")
47 clk.advance(5*time.Minute + time.Second)
48 a.sweepOnce()
49 waitFor(t, "box-default sleep", func() bool { return a.entryCount() == 0 })
50}
51
52func TestIdleForShortensAWorkerToTheSmaller(t *testing.T) {
53 t.Parallel()
54 for _, c := range []struct {
55 name string
56 worker int
57 plan, sleep time.Duration
58 }{
59 {"plan shorter than the worker's own", 600, 90 * time.Second, 90 * time.Second},
60 {"worker's own shorter than the plan", 60, 90 * time.Second, 60 * time.Second},
61 } {
62 a, _, clk, _ := testActivator(t, time.Hour)
63 a.SetIdleFor(idleFor(c.plan))
64 rt := testWorkerRoute("bot.x.internal")
65 rt.IdleSeconds = c.worker
66 if err := a.WakeWorker(rt); err != nil {
67 t.Fatalf("%s: WakeWorker: %v", c.name, err)
68 }
69 clk.advance(c.sleep - 5*time.Second)
70 a.sweepOnce()
71 if !a.entryAwake("bot.x.internal") {
72 t.Fatalf("%s: slept early", c.name)
73 }
74 clk.advance(6 * time.Second)
75 a.sweepOnce()
76 waitFor(t, c.name, func() bool { return a.entryCount() == 0 })
77 }
78}
79
80func TestIdleForNilOrZeroChangesNothing(t *testing.T) {
81 t.Parallel()
82 for name, hook := range map[string]func(registry.Route) time.Duration{"nil": nil, "zero": idleFor(0)} {
83 a, _, clk, _ := testActivator(t, 10*time.Second)
84 a.SetIdleFor(hook)
85 wakeInstance(t, a, "one.example.com")
86 clk.advance(9 * time.Second)
87 a.sweepOnce()
88 if a.entryCount() != 1 {
89 t.Fatalf("%s hook: slept before the box default", name)
90 }
91 clk.advance(2 * time.Second)
92 a.sweepOnce()
93 waitFor(t, name+" hook: default sleep", func() bool { return a.entryCount() == 0 })
94 }
95}
96
97func TestIdleForLeavesAlwaysOnWorkersAlone(t *testing.T) {
98 t.Parallel()
99 a, _, clk, _ := testActivator(t, time.Hour)
100 a.SetIdleFor(idleFor(90 * time.Second))
101 rt := testWorkerRoute("bot.x.internal")
102 rt.Hibernate = false
103 if err := a.WakeWorker(rt); err != nil {
104 t.Fatalf("WakeWorker: %v", err)
105 }
106 for i := 0; i < 5; i++ {
107 clk.advance(time.Hour)
108 a.sweepOnce()
109 }
110 if a.entryCount() != 1 {
111 t.Fatal("an always-on worker was stopped by the plan's idle window")
112 }
113}
114