package main
import (
"errors"
"os"
"path/filepath"
"regexp"
"testing"
"time"
"craftdesign.group/quarry/internal/events"
"craftdesign.group/quarry/internal/lease"
)
var nodeIDShape = regexp.MustCompile(`^[0-9a-f]{12}$`)
func TestNodeIDSurvivesARestart(t *testing.T) {
dir := t.TempDir()
first, err := nodeID("", dir)
if err != nil {
t.Fatal(err)
}
if !nodeIDShape.MatchString(first) {
t.Fatalf("FAIL: first id %q is not 12 hex", first)
}
again, err := nodeID("", dir)
if err != nil {
t.Fatal(err)
}
if again != first {
t.Fatalf("FAIL: same data dir gave %q then %q", first, again)
}
fi, err := os.Stat(filepath.Join(dir, "node-id"))
if err != nil {
t.Fatalf("FAIL: no node-id file: %v", err)
}
if fi.Mode().Perm() != 0o600 {
t.Errorf("FAIL: node-id mode %v, want 0600", fi.Mode().Perm())
}
if left, _ := filepath.Glob(filepath.Join(dir, "node-id.*")); len(left) != 0 {
t.Errorf("FAIL: temp files left beside node-id: %v", left)
}
}
func TestNodeIDDiffersAcrossDataDirs(t *testing.T) {
a, err := nodeID("", t.TempDir())
if err != nil {
t.Fatal(err)
}
b, err := nodeID("", t.TempDir())
if err != nil {
t.Fatal(err)
}
if a == b {
t.Fatalf("FAIL: two data dirs share id %q", a)
}
}
func TestNodeIDFlagWinsOverTheFile(t *testing.T) {
dir := t.TempDir()
stored, err := nodeID("", dir)
if err != nil {
t.Fatal(err)
}
got, err := nodeID("edge-1", dir)
if err != nil {
t.Fatal(err)
}
if got != "edge-1" {
t.Fatalf("FAIL: override gave %q, want edge-1", got)
}
if back, _ := nodeID("", dir); back != stored {
t.Errorf("FAIL: override rewrote the stored id: %q, want %q", back, stored)
}
}
func TestNodeIDRefusesAnEmptyFile(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "node-id"), []byte("\n"), 0o600); err != nil {
t.Fatal(err)
}
if id, err := nodeID("", dir); err == nil {
t.Fatalf("FAIL: empty node-id file accepted as %q", id)
}
}
// Two nodes behind local proxies both listen on the default --addr. The
// lease owner is the node id, so they must still contend rather than
// each accepting the other's hold as its own.
func TestNodesOnOneAddrDoNotShareALease(t *testing.T) {
ev, err := events.Start(t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(ev.Close)
var mgrs []*lease.Manager
for range 2 {
id, err := nodeID("", t.TempDir())
if err != nil {
t.Fatal(err)
}
m, err := lease.New(ev.JS(), id, time.Second)
if err != nil {
t.Fatal(err)
}
t.Cleanup(m.Close)
mgrs = append(mgrs, m)
}
if err := mgrs[0].Guard("repo1", func(lease.Token) error { return nil }); err != nil {
t.Fatalf("FAIL: first node refused: %v", err)
}
if err := mgrs[1].Guard("repo1", func(lease.Token) error { return nil }); !errors.Is(err, lease.ErrNotHolder) {
t.Fatalf("FAIL: second node on the same addr got %v, want ErrNotHolder", err)
}
}