package mtls import ( "context" "strings" "testing" "time" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" ) func newTestBootstrapManager(t *testing.T) (*BootstrapTokenManager, *miniredis.Miniredis) { t.Helper() mr := miniredis.RunT(t) rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()}) t.Cleanup(func() { rdb.Close() }) return NewBootstrapTokenManager(rdb), mr } func TestBootstrap_IssueToken_Format(t *testing.T) { mgr, _ := newTestBootstrapManager(t) token, err := mgr.IssueToken(context.Background(), "node-abc") if err != nil { t.Fatalf("IssueToken: %v", err) } if len(token) != 64 { t.Errorf("token length = %d; want 64 hex chars", len(token)) } if strings.ContainsAny(token, "ghijklmnopqrstuvwxyz !@#") { t.Errorf("token contains non-hex chars: %q", token) } } func TestBootstrap_ConsumeToken_OnceOnly(t *testing.T) { mgr, _ := newTestBootstrapManager(t) ctx := context.Background() const nodeUUID = "node-11111111-2222-3333-4444-555555555555" token, err := mgr.IssueToken(ctx, nodeUUID) if err != nil { t.Fatalf("IssueToken: %v", err) } // First consume: must succeed. got, err := mgr.ConsumeToken(ctx, token) if err != nil { t.Fatalf("ConsumeToken (first): %v", err) } if got != nodeUUID { t.Errorf("ConsumeToken returned %q; want %q", got, nodeUUID) } // Second consume: must fail (one-time guarantee). _, err = mgr.ConsumeToken(ctx, token) if err == nil { t.Fatal("ConsumeToken (second): expected error for already-consumed token, got nil") } } func TestBootstrap_ConsumeToken_NeverIssued(t *testing.T) { mgr, _ := newTestBootstrapManager(t) _, err := mgr.ConsumeToken(context.Background(), "deadbeefdeadbeef") if err == nil { t.Fatal("expected error for non-existent token, got nil") } } func TestBootstrap_ConsumeToken_ExpiredTTL(t *testing.T) { mgr, mr := newTestBootstrapManager(t) ctx := context.Background() token, err := mgr.IssueToken(ctx, "node-expired") if err != nil { t.Fatalf("IssueToken: %v", err) } // Advance miniredis clock past the 15-minute TTL. mr.FastForward(bootstrapTokenTTL + time.Second) _, err = mgr.ConsumeToken(ctx, token) if err == nil { t.Fatal("expected error after TTL expiry, got nil") } } func TestBootstrap_IssueToken_Uniqueness(t *testing.T) { mgr, _ := newTestBootstrapManager(t) ctx := context.Background() t1, _ := mgr.IssueToken(ctx, "node-A") t2, _ := mgr.IssueToken(ctx, "node-B") if t1 == t2 { t.Error("IssueToken returned duplicate tokens for different nodes") } }