Files
sultan/pkg/store/v4_test.go
T
br ca6cdcca63 software steht so weit.
jetzt build + docker build und testen
2026-10-02 13:25:34 +02:00

156 lines
4.8 KiB
Go

package store
import (
"errors"
"reflect"
"testing"
"time"
)
func TestLeases(t *testing.T) {
s, clock := openTest(t)
mustTenant(t, s, "t1")
mustNode(t, s, "n1", "t1", "k1")
if _, err := s.GetLease(ctx, "n1"); !errors.Is(err, ErrNotFound) {
t.Errorf("ohne Lease: %v", err)
}
l := Lease{
NodeID: "n1",
IssuedAt: clock.now(),
RenewAfter: clock.now().Add(7 * 24 * time.Hour),
ValidUntil: clock.now().Add(14 * 24 * time.Hour),
Document: `{"node_id":"n1"}`,
}
if err := s.PutLease(ctx, l); err != nil {
t.Fatalf("PutLease: %v", err)
}
got, err := s.GetLease(ctx, "n1")
if err != nil || !reflect.DeepEqual(got, l) {
t.Errorf("GetLease = %+v, %v", got, err)
}
l.ValidUntil = l.ValidUntil.Add(time.Hour)
if err := s.PutLease(ctx, l); err != nil {
t.Fatal(err)
}
if got, _ := s.GetLease(ctx, "n1"); !got.ValidUntil.Equal(l.ValidUntil) {
t.Error("PutLease ersetzt nicht")
}
if err := s.PutLease(ctx, Lease{NodeID: "fehlt", Document: "{}"}); !errors.Is(err, ErrNotFound) {
t.Errorf("unbekannter Knoten: %v", err)
}
s.DeleteNode(ctx, "n1")
if _, err := s.GetLease(ctx, "n1"); !errors.Is(err, ErrNotFound) {
t.Error("Lease nach Löschen des Knotens noch da")
}
}
func TestTenantFeaturesAndPayment(t *testing.T) {
s, clock := openTest(t)
in := sampleTenant("t1")
in.Features = []string{"custom_middleware", "websockets"}
created, err := s.CreateTenant(ctx, in)
if err != nil {
t.Fatal(err)
}
got, _ := s.GetTenant(ctx, "t1")
if !reflect.DeepEqual(got.Features, []string{"custom_middleware", "websockets"}) || !reflect.DeepEqual(got, created) {
t.Errorf("Features: %+v", got.Features)
}
if !got.PaymentOverdueSince.IsZero() {
t.Error("neuer Mandant mit offener Zahlung")
}
if def, _ := s.CreateTenant(ctx, sampleTenant("t2")); def.Features == nil || len(def.Features) != 0 {
t.Errorf("Default-Features: %#v", def.Features)
}
due := clock.now().Add(-10 * 24 * time.Hour)
if err := s.SetTenantPayment(ctx, "t1", due); err != nil {
t.Fatal(err)
}
if got, _ := s.GetTenant(ctx, "t1"); !got.PaymentOverdueSince.Equal(due) {
t.Errorf("offen seit: %v", got.PaymentOverdueSince)
}
if err := s.SetTenantPayment(ctx, "t1", time.Time{}); err != nil {
t.Fatal(err)
}
if got, _ := s.GetTenant(ctx, "t1"); !got.PaymentOverdueSince.IsZero() {
t.Error("bezahlt: Fälligkeit nicht gelöscht")
}
if err := s.SetTenantPayment(ctx, "fehlt", due); !errors.Is(err, ErrNotFound) {
t.Errorf("unbekannter Mandant: %v", err)
}
bad := sampleTenant("t3")
bad.Features = []string{"ok", " "}
if _, err := s.CreateTenant(ctx, bad); !errors.Is(err, ErrInvalid) {
t.Errorf("leeres Feature: %v", err)
}
}
func TestEnroll_RecordsUsedAt(t *testing.T) {
s, clock := openTest(t)
mustTenant(t, s, "t1")
s.AddEnrollmentToken(ctx, "tok", "t1", clock.now().Add(time.Hour))
clock.advance(time.Minute)
if _, err := s.Enroll(ctx, "tok", sampleNode("n1", "k1")); err != nil {
t.Fatal(err)
}
var usedAt time.Time
if err := s.db.QueryRowContext(ctx, "SELECT used_at FROM enrollment_tokens").Scan(dbTime{&usedAt}); err != nil {
t.Fatal(err)
}
if !usedAt.Equal(clock.now()) {
t.Errorf("used_at = %v, erwartet %v", usedAt, clock.now())
}
}
func TestNodeCommands(t *testing.T) {
s, clock := openTest(t)
mustTenant(t, s, "t1")
mustNode(t, s, "n1", "t1", "k1")
if err := s.EnqueueNodeCommand(ctx, "n1", "resync", ""); err != nil {
t.Fatal(err)
}
clock.advance(time.Second)
s.EnqueueNodeCommand(ctx, "n1", "drain", "Umzug")
cmds, err := s.PendingNodeCommands(ctx, "n1")
if err != nil || len(cmds) != 2 || cmds[0].Command != "resync" || cmds[1].Command != "drain" || cmds[1].Reason != "Umzug" {
t.Fatalf("ausstehend: %+v %v", cmds, err)
}
if err := s.MarkNodeCommandSent(ctx, cmds[0].ID); err != nil {
t.Fatal(err)
}
if cmds, _ := s.PendingNodeCommands(ctx, "n1"); len(cmds) != 1 || cmds[0].Command != "drain" {
t.Errorf("nach Versand: %+v", cmds)
}
if err := s.EnqueueNodeCommand(ctx, "fehlt", "resync", ""); !errors.Is(err, ErrNotFound) {
t.Errorf("unbekannter Knoten: %v", err)
}
if err := s.EnqueueNodeCommand(ctx, "n1", "", ""); !errors.Is(err, ErrInvalid) {
t.Errorf("leerer Befehl: %v", err)
}
}
func TestUpdateNodePublicKey(t *testing.T) {
s, _ := openTest(t)
mustTenant(t, s, "t1")
mustNode(t, s, "n1", "t1", "k1")
mustNode(t, s, "n2", "t1", "k2")
if err := s.UpdateNodePublicKey(ctx, "n1", "k1-neu"); err != nil {
t.Fatal(err)
}
if n, _ := s.GetNodeByPublicKey(ctx, "k1-neu"); n.ID != "n1" {
t.Errorf("neuer Schlüssel nicht gefunden: %+v", n)
}
if _, err := s.GetNodeByPublicKey(ctx, "k1"); !errors.Is(err, ErrNotFound) {
t.Error("alter Schlüssel noch gültig")
}
if err := s.UpdateNodePublicKey(ctx, "n1", "k2"); !errors.Is(err, ErrExists) {
t.Errorf("fremder Schlüssel: %v", err)
}
if err := s.UpdateNodePublicKey(ctx, "fehlt", "x"); !errors.Is(err, ErrNotFound) {
t.Errorf("unbekannter Knoten: %v", err)
}
}