Initial commit.

This commit is contained in:
jdl
2026-06-14 16:35:50 +02:00
parent b66c2310ed
commit 5aec8fa016
4 changed files with 195 additions and 1 deletions

125
idgen_test.go Normal file
View File

@@ -0,0 +1,125 @@
package idgen
import (
"testing"
"testing/synctest"
"time"
)
func TestNewToken_length(t *testing.T) {
tok := NewToken()
if len(tok) != 32 {
t.Fatalf("expected 32 chars, got %d: %q", len(tok), tok)
}
}
func TestNewToken_validBase32(t *testing.T) {
tok := NewToken()
if _, err := encoding.DecodeString(tok); err != nil {
t.Fatalf("invalid base32: %v", err)
}
}
func TestNewToken_unique(t *testing.T) {
seen := make(map[string]bool, 100)
for range 100 {
tok := NewToken()
if seen[tok] {
t.Fatal("duplicate token generated")
}
seen[tok] = true
}
}
func TestNextID_roundtrip(t *testing.T) {
const nodeID = 42
before := time.Now().Unix()
id := NextID(nodeID)
after := time.Now().Unix()
gotTime, gotNode, gotSeq := SplitID(id)
if gotNode != nodeID {
t.Errorf("nodeID: got %d, want %d", gotNode, nodeID)
}
if gotTime < before || gotTime > after {
t.Errorf("timestamp %d out of range [%d, %d]", gotTime, before, after)
}
if gotSeq < 1 {
t.Errorf("seq should be >= 1, got %d", gotSeq)
}
}
func TestNextID_allNodeIDs(t *testing.T) {
for nodeID := int64(0); nodeID < 64; nodeID++ {
id := NextID(nodeID)
_, got, _ := SplitID(id)
if got != nodeID {
t.Errorf("nodeID %d: SplitID returned %d", nodeID, got)
}
}
}
func TestNextID_monotonic(t *testing.T) {
prev := NextID(0)
for range 1000 {
id := NextID(0)
if id <= prev {
t.Fatalf("not monotonically increasing: %d <= %d", id, prev)
}
prev = id
}
}
func TestNextID_unique(t *testing.T) {
seen := make(map[int64]bool, 1000)
for i := range 1000 {
id := NextID(0)
if seen[id] {
t.Fatalf("duplicate ID at i=%d", i)
}
seen[id] = true
}
}
func TestNextID_invalidNodeID(t *testing.T) {
for _, bad := range []int64{-1, 64, 100} {
func() {
defer func() {
if recover() == nil {
t.Errorf("NextID(%d) should have panicked", bad)
}
}()
NextID(bad)
}()
}
}
func TestNextID_timestampAdvances(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
// synctest's synthetic clock starts at 2000-01-01 00:00:00 UTC.
// Prime ts to one second before that so the first NextID call
// enters the new-second branch and records the synthetic start time.
lock.Lock()
ts = time.Now().Unix() - 1
seq = 0
lock.Unlock()
id1 := NextID(0)
t1, _, _ := SplitID(id1)
time.Sleep(2 * time.Second)
id2 := NextID(0)
t2, _, _ := SplitID(id2)
if t2 <= t1 {
t.Errorf("timestamp did not advance: %d -> %d", t1, t2)
}
})
}
func BenchmarkNextID(b *testing.B) {
for b.Loop() {
NextID(0)
}
}