blob: 5adc408fb92a6c42a59e1b224276b4cd6883bad0 [file] [log] [blame]
package manager
import (
"context"
"testing"
"time"
"golang.org/x/time/rate"
"source.monogon.dev/cloud/bmaas/bmdb"
"source.monogon.dev/cloud/bmaas/bmdb/model"
"source.monogon.dev/cloud/lib/component"
"source.monogon.dev/cloud/shepherd"
)
// TestProvisionerSmokes makes sure the Provisioner doesn't go up in flames on
// the happy path.
func TestProvisionerSmokes(t *testing.T) {
pc := ProvisionerConfig{
MaxCount: 10,
// We need 3 iterations to provide 10 machines with a chunk size of 4.
ReconcileLoopLimiter: rate.NewLimiter(rate.Every(10*time.Second), 3),
DeviceCreationLimiter: rate.NewLimiter(rate.Every(time.Second), 10),
ChunkSize: 4,
}
provider := newDummyProvider(100)
p, err := NewProvisioner(provider, pc)
if err != nil {
t.Fatalf("Could not create Provisioner: %v", err)
}
ctx, ctxC := context.WithCancel(context.Background())
defer ctxC()
b := bmdb.BMDB{
Config: bmdb.Config{
Database: component.CockroachConfig{
InMemory: true,
},
ComponentName: "test",
RuntimeInfo: "test",
},
}
conn, err := b.Open(true)
if err != nil {
t.Fatalf("Could not create in-memory BMDB: %v", err)
}
go p.Run(ctx, conn)
sess, err := conn.StartSession(ctx)
if err != nil {
t.Fatalf("Failed to create BMDB session for verification: %v", err)
}
for {
time.Sleep(100 * time.Millisecond)
var provided []model.MachineProvided
err = sess.Transact(ctx, func(q *model.Queries) error {
var err error
provided, err = q.GetProvidedMachines(ctx, provider.Type())
return err
})
if err != nil {
t.Errorf("Transact failed: %v", err)
}
if len(provided) < 10 {
continue
}
if len(provided) > 10 {
t.Errorf("%d machines provided (limit: 10)", len(provided))
}
for _, mp := range provided {
if provider.machines[shepherd.ProviderID(mp.ProviderID)] == nil {
t.Errorf("BMDB machine %q has unknown provider ID %q", mp.MachineID, mp.ProviderID)
}
}
return
}
}
// TestProvisioner_resolvePossiblyUsed makes sure the PossiblyUsed state is
// resolved correctly.
func TestProvisioner_resolvePossiblyUsed(t *testing.T) {
const providedMachineID = "provided-machine"
providedMachines := map[shepherd.ProviderID]bool{
providedMachineID: true,
}
tests := []struct {
name string
machineID shepherd.ProviderID
machineState shepherd.State
wantedState shepherd.State
}{
{
name: "skip KnownUsed",
machineState: shepherd.StateKnownUsed,
wantedState: shepherd.StateKnownUsed,
},
{
name: "skip KnownUnused",
machineState: shepherd.StateKnownUnused,
wantedState: shepherd.StateKnownUnused,
},
{
name: "invalid ID",
machineID: shepherd.InvalidProviderID,
machineState: shepherd.StatePossiblyUsed,
wantedState: shepherd.StateKnownUnused,
},
{
name: "valid ID, not in providedMachines",
machineID: "unused-machine",
machineState: shepherd.StatePossiblyUsed,
wantedState: shepherd.StateKnownUnused,
},
{
name: "valid ID, in providedMachines",
machineID: providedMachineID,
machineState: shepherd.StatePossiblyUsed,
wantedState: shepherd.StateKnownUsed,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Provisioner{}
if got := p.resolvePossiblyUsed(&dummyMachine{id: tt.machineID, state: tt.machineState}, providedMachines); got != tt.wantedState {
t.Errorf("resolvePossiblyUsed() = %v, want %v", got, tt.wantedState)
}
})
}
}