blob: 5adc408fb92a6c42a59e1b224276b4cd6883bad0 [file] [log] [blame]
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +02001package manager
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "golang.org/x/time/rate"
9
10 "source.monogon.dev/cloud/bmaas/bmdb"
11 "source.monogon.dev/cloud/bmaas/bmdb/model"
12 "source.monogon.dev/cloud/lib/component"
13 "source.monogon.dev/cloud/shepherd"
14)
15
16// TestProvisionerSmokes makes sure the Provisioner doesn't go up in flames on
17// the happy path.
18func TestProvisionerSmokes(t *testing.T) {
19 pc := ProvisionerConfig{
20 MaxCount: 10,
21 // We need 3 iterations to provide 10 machines with a chunk size of 4.
22 ReconcileLoopLimiter: rate.NewLimiter(rate.Every(10*time.Second), 3),
23 DeviceCreationLimiter: rate.NewLimiter(rate.Every(time.Second), 10),
24 ChunkSize: 4,
25 }
26
27 provider := newDummyProvider(100)
28
29 p, err := NewProvisioner(provider, pc)
30 if err != nil {
31 t.Fatalf("Could not create Provisioner: %v", err)
32 }
33
34 ctx, ctxC := context.WithCancel(context.Background())
35 defer ctxC()
36
37 b := bmdb.BMDB{
38 Config: bmdb.Config{
39 Database: component.CockroachConfig{
40 InMemory: true,
41 },
42 ComponentName: "test",
43 RuntimeInfo: "test",
44 },
45 }
46 conn, err := b.Open(true)
47 if err != nil {
48 t.Fatalf("Could not create in-memory BMDB: %v", err)
49 }
50
51 go p.Run(ctx, conn)
52
53 sess, err := conn.StartSession(ctx)
54 if err != nil {
55 t.Fatalf("Failed to create BMDB session for verification: %v", err)
56 }
57 for {
58 time.Sleep(100 * time.Millisecond)
59
60 var provided []model.MachineProvided
61 err = sess.Transact(ctx, func(q *model.Queries) error {
62 var err error
63 provided, err = q.GetProvidedMachines(ctx, provider.Type())
64 return err
65 })
66 if err != nil {
67 t.Errorf("Transact failed: %v", err)
68 }
69 if len(provided) < 10 {
70 continue
71 }
72 if len(provided) > 10 {
73 t.Errorf("%d machines provided (limit: 10)", len(provided))
74 }
75
76 for _, mp := range provided {
77 if provider.machines[shepherd.ProviderID(mp.ProviderID)] == nil {
78 t.Errorf("BMDB machine %q has unknown provider ID %q", mp.MachineID, mp.ProviderID)
79 }
80 }
81
82 return
83 }
84}
85
86// TestProvisioner_resolvePossiblyUsed makes sure the PossiblyUsed state is
87// resolved correctly.
88func TestProvisioner_resolvePossiblyUsed(t *testing.T) {
89 const providedMachineID = "provided-machine"
90
91 providedMachines := map[shepherd.ProviderID]bool{
92 providedMachineID: true,
93 }
94
95 tests := []struct {
96 name string
97 machineID shepherd.ProviderID
98 machineState shepherd.State
99 wantedState shepherd.State
100 }{
101 {
102 name: "skip KnownUsed",
103 machineState: shepherd.StateKnownUsed,
104 wantedState: shepherd.StateKnownUsed,
105 },
106 {
107 name: "skip KnownUnused",
108 machineState: shepherd.StateKnownUnused,
109 wantedState: shepherd.StateKnownUnused,
110 },
111 {
112 name: "invalid ID",
113 machineID: shepherd.InvalidProviderID,
114 machineState: shepherd.StatePossiblyUsed,
115 wantedState: shepherd.StateKnownUnused,
116 },
117 {
118 name: "valid ID, not in providedMachines",
119 machineID: "unused-machine",
120 machineState: shepherd.StatePossiblyUsed,
121 wantedState: shepherd.StateKnownUnused,
122 },
123 {
124 name: "valid ID, in providedMachines",
125 machineID: providedMachineID,
126 machineState: shepherd.StatePossiblyUsed,
127 wantedState: shepherd.StateKnownUsed,
128 },
129 }
130 for _, tt := range tests {
131 t.Run(tt.name, func(t *testing.T) {
132 p := &Provisioner{}
133 if got := p.resolvePossiblyUsed(&dummyMachine{id: tt.machineID, state: tt.machineState}, providedMachines); got != tt.wantedState {
134 t.Errorf("resolvePossiblyUsed() = %v, want %v", got, tt.wantedState)
135 }
136 })
137 }
138}