2026-08-24 10:29:08 +03:00
|
|
|
package db
|
|
|
|
|
|
|
|
|
|
import (
|
2026-09-13 23:54:35 +03:00
|
|
|
"errors"
|
2026-08-24 10:29:08 +03:00
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestSetFIPAssociatedStampsTimestamp(t *testing.T) {
|
|
|
|
|
d, ctx := newTestDB(t)
|
|
|
|
|
|
|
|
|
|
if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil {
|
|
|
|
|
t.Fatalf("seed queue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.AdminCreateValidator(ctx, "validator-1", "port-1"); err != nil {
|
|
|
|
|
t.Fatalf("create validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
claimed, err := d.ClaimNextQueued(ctx, "validator-1", time.Minute)
|
|
|
|
|
if err != nil || claimed == nil {
|
|
|
|
|
t.Fatalf("claim: item=%+v err=%v", claimed, err)
|
|
|
|
|
}
|
|
|
|
|
if claimed.FIPAssociatedAt != nil {
|
|
|
|
|
t.Fatalf("expected FIPAssociatedAt nil before association, got %v", claimed.FIPAssociatedAt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
before := Now()
|
|
|
|
|
if err := d.SetFIPAssociated(ctx, claimed.ID, "fip-1", time.Minute); err != nil {
|
|
|
|
|
t.Fatalf("set fip associated: %v", err)
|
|
|
|
|
}
|
|
|
|
|
item, err := d.GetIP(ctx, claimed.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("get ip: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if item.FIPAssociatedAt == nil {
|
|
|
|
|
t.Fatalf("expected FIPAssociatedAt to be set")
|
|
|
|
|
}
|
|
|
|
|
if item.FIPAssociatedAt.Before(before) {
|
|
|
|
|
t.Fatalf("expected FIPAssociatedAt >= %v, got %v", before, *item.FIPAssociatedAt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-13 23:54:35 +03:00
|
|
|
func TestMarkFIPOccupiedIsTerminalAndFreesValidator(t *testing.T) {
|
|
|
|
|
d, ctx := newTestDB(t)
|
|
|
|
|
|
|
|
|
|
if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil {
|
|
|
|
|
t.Fatalf("seed queue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.AdminCreateValidator(ctx, "validator-1", "port-1"); err != nil {
|
|
|
|
|
t.Fatalf("create validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
claimed, err := d.ClaimNextQueued(ctx, "validator-1", time.Minute)
|
|
|
|
|
if err != nil || claimed == nil {
|
|
|
|
|
t.Fatalf("claim: item=%+v err=%v", claimed, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := d.MarkFIPOccupied(ctx, claimed.ID, "validator-1"); err != nil {
|
|
|
|
|
t.Fatalf("mark fip occupied: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item, err := d.GetIP(ctx, claimed.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("get ip: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if item.State != IPOccupied {
|
|
|
|
|
t.Fatalf("expected occupied, got state=%s", item.State)
|
|
|
|
|
}
|
|
|
|
|
if item.OwnerValidatorID != nil {
|
|
|
|
|
t.Fatalf("expected owner cleared, got %v", *item.OwnerValidatorID)
|
|
|
|
|
}
|
|
|
|
|
if item.FIPID != "" {
|
|
|
|
|
t.Fatalf("expected fip_id cleared, got %q", item.FIPID)
|
|
|
|
|
}
|
|
|
|
|
if item.LeaseExpiresAt != nil {
|
|
|
|
|
t.Fatalf("expected lease cleared, got %v", item.LeaseExpiresAt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v, err := d.GetValidator(ctx, "validator-1")
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("get validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if v.State != ValidatorIdle || v.CurrentIPID != nil {
|
|
|
|
|
t.Fatalf("expected validator freed to idle, got state=%s current_ip=%v", v.State, v.CurrentIPID)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSubmitIPsResubmitsOccupiedAddress(t *testing.T) {
|
|
|
|
|
d, ctx := newTestDB(t)
|
|
|
|
|
|
|
|
|
|
if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil {
|
|
|
|
|
t.Fatalf("seed queue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.AdminCreateValidator(ctx, "validator-1", "port-1"); err != nil {
|
|
|
|
|
t.Fatalf("create validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
claimed, err := d.ClaimNextQueued(ctx, "validator-1", time.Minute)
|
|
|
|
|
if err != nil || claimed == nil {
|
|
|
|
|
t.Fatalf("claim: item=%+v err=%v", claimed, err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.MarkFIPOccupied(ctx, claimed.ID, "validator-1"); err != nil {
|
|
|
|
|
t.Fatalf("mark fip occupied: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result, err := d.SubmitIPs(ctx, []string{"1.2.3.4"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("submit ips: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(result.Requeued) != 1 || result.Requeued[0] != "1.2.3.4" {
|
|
|
|
|
t.Fatalf("expected address requeued, got %+v", result)
|
|
|
|
|
}
|
|
|
|
|
if len(result.SkippedInProgress) != 0 {
|
|
|
|
|
t.Fatalf("expected nothing skipped as in-progress, got %+v", result.SkippedInProgress)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item, err := d.GetIP(ctx, claimed.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("get ip: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if item.State != IPQueued {
|
|
|
|
|
t.Fatalf("expected queued after resubmit, got state=%s", item.State)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestCancelIPRejectsAlreadyOccupied(t *testing.T) {
|
|
|
|
|
d, ctx := newTestDB(t)
|
|
|
|
|
|
|
|
|
|
if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil {
|
|
|
|
|
t.Fatalf("seed queue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.AdminCreateValidator(ctx, "validator-1", "port-1"); err != nil {
|
|
|
|
|
t.Fatalf("create validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
claimed, err := d.ClaimNextQueued(ctx, "validator-1", time.Minute)
|
|
|
|
|
if err != nil || claimed == nil {
|
|
|
|
|
t.Fatalf("claim: item=%+v err=%v", claimed, err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.MarkFIPOccupied(ctx, claimed.ID, "validator-1"); err != nil {
|
|
|
|
|
t.Fatalf("mark fip occupied: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = d.CancelIP(ctx, claimed.ID)
|
|
|
|
|
if !errors.Is(err, ErrInvalidState) {
|
|
|
|
|
t.Fatalf("expected ErrInvalidState cancelling an occupied ip, got %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 10:29:08 +03:00
|
|
|
func TestRequeueClearsFIPAssociatedAt(t *testing.T) {
|
|
|
|
|
d, ctx := newTestDB(t)
|
|
|
|
|
|
|
|
|
|
if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil {
|
|
|
|
|
t.Fatalf("seed queue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.AdminCreateValidator(ctx, "validator-1", "port-1"); err != nil {
|
|
|
|
|
t.Fatalf("create validator: %v", err)
|
|
|
|
|
}
|
|
|
|
|
claimed, err := d.ClaimNextQueued(ctx, "validator-1", time.Minute)
|
|
|
|
|
if err != nil || claimed == nil {
|
|
|
|
|
t.Fatalf("claim: item=%+v err=%v", claimed, err)
|
|
|
|
|
}
|
|
|
|
|
if err := d.SetFIPAssociated(ctx, claimed.ID, "fip-1", time.Minute); err != nil {
|
|
|
|
|
t.Fatalf("set fip associated: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := d.RequeueOrFail(ctx, claimed.ID, "validator-1", 3); err != nil {
|
|
|
|
|
t.Fatalf("requeue or fail: %v", err)
|
|
|
|
|
}
|
|
|
|
|
item, err := d.GetIP(ctx, claimed.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("get ip after requeue: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if item.State != IPQueued {
|
|
|
|
|
t.Fatalf("expected requeued, got state=%s", item.State)
|
|
|
|
|
}
|
|
|
|
|
if item.FIPAssociatedAt != nil {
|
|
|
|
|
t.Fatalf("expected FIPAssociatedAt cleared on requeue, got %v", item.FIPAssociatedAt)
|
|
|
|
|
}
|
|
|
|
|
}
|