Skip to content

Commit 3c625b8

Browse files
committed
Updated testing code
1 parent 4dea741 commit 3c625b8

2 files changed

Lines changed: 239 additions & 58 deletions

File tree

hyperflake_test.go

Lines changed: 148 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package hyperflake
22

33
import (
4+
"sync"
45
"testing"
56
)
67

8+
// TestDecodeID verifies that known IDs decode to the expected components.
79
func TestDecodeID(t *testing.T) {
810
hf := NewHyperflakeConfig(0, 0)
911

1012
testCases := []struct {
13+
name string
1114
id int64
1215
expectedSignbit int
1316
expectedTimestamp int64
@@ -16,6 +19,7 @@ func TestDecodeID(t *testing.T) {
1619
expectedSequenceNumber int
1720
}{
1821
{
22+
name: "zero datacenter and machine ID",
1923
id: 3282575599297626112,
2024
expectedSignbit: 0,
2125
expectedTimestamp: 1729311810178,
@@ -24,6 +28,7 @@ func TestDecodeID(t *testing.T) {
2428
expectedSequenceNumber: 0,
2529
},
2630
{
31+
name: "non-zero datacenter, machine ID and sequence number",
2732
id: 3273974649684016911,
2833
expectedSignbit: 0,
2934
expectedTimestamp: 1727261183992,
@@ -34,30 +39,159 @@ func TestDecodeID(t *testing.T) {
3439
}
3540

3641
for _, tc := range testCases {
37-
t.Run("", func(t *testing.T) {
38-
decodedID, err := hf.DecodeID(tc.id)
42+
t.Run(tc.name, func(t *testing.T) {
43+
decoded, err := hf.DecodeID(tc.id)
3944
if err != nil {
4045
t.Fatalf("DecodeID(%d) returned error: %v", tc.id, err)
4146
}
42-
if decodedID.Signbit != tc.expectedSignbit {
43-
t.Errorf("DecodeID(%d) Signbit = %d; want %d", tc.id, decodedID.Signbit, tc.expectedSignbit)
47+
if decoded.Signbit != tc.expectedSignbit {
48+
t.Errorf("Signbit = %d; want %d", decoded.Signbit, tc.expectedSignbit)
4449
}
45-
if decodedID.Timestamp != tc.expectedTimestamp {
46-
t.Errorf("DecodeID(%d) Timestamp = %d; want %d", tc.id, decodedID.Timestamp, tc.expectedTimestamp)
50+
if decoded.Timestamp != tc.expectedTimestamp {
51+
t.Errorf("Timestamp = %d; want %d", decoded.Timestamp, tc.expectedTimestamp)
4752
}
48-
if decodedID.DatacenterID != tc.expectedDatacenterID {
49-
t.Errorf("DecodeID(%d) DatacenterID = %d; want %d", tc.id, decodedID.DatacenterID, tc.expectedDatacenterID)
53+
if decoded.DatacenterID != tc.expectedDatacenterID {
54+
t.Errorf("DatacenterID = %d; want %d", decoded.DatacenterID, tc.expectedDatacenterID)
5055
}
51-
if decodedID.MachineID != tc.expectedMachineID {
52-
t.Errorf("DecodeID(%d) MachineID = %d; want %d", tc.id, decodedID.MachineID, tc.expectedMachineID)
56+
if decoded.MachineID != tc.expectedMachineID {
57+
t.Errorf("MachineID = %d; want %d", decoded.MachineID, tc.expectedMachineID)
5358
}
54-
if decodedID.SequenceNumber != tc.expectedSequenceNumber {
55-
t.Errorf("DecodeID(%d) SequenceNumber = %d; want %d", tc.id, decodedID.SequenceNumber, tc.expectedSequenceNumber)
59+
if decoded.SequenceNumber != tc.expectedSequenceNumber {
60+
t.Errorf("SequenceNumber = %d; want %d", decoded.SequenceNumber, tc.expectedSequenceNumber)
5661
}
5762
})
5863
}
64+
}
65+
66+
// TestGenerateAndDecode verifies that a generated ID round-trips correctly through DecodeID.
67+
func TestGenerateAndDecode(t *testing.T) {
68+
const datacenterID = 12
69+
const machineID = 7
70+
71+
config := NewHyperflakeConfig(datacenterID, machineID)
72+
id, err := config.GenerateHyperflakeID()
73+
if err != nil {
74+
t.Fatalf("GenerateHyperflakeID() error: %v", err)
75+
}
76+
if id <= 0 {
77+
t.Fatalf("GenerateHyperflakeID() returned non-positive ID: %d", id)
78+
}
79+
80+
decoded, err := config.DecodeID(id)
81+
if err != nil {
82+
t.Fatalf("DecodeID(%d) error: %v", id, err)
83+
}
84+
if decoded.DatacenterID != datacenterID {
85+
t.Errorf("DatacenterID = %d; want %d", decoded.DatacenterID, datacenterID)
86+
}
87+
if decoded.MachineID != machineID {
88+
t.Errorf("MachineID = %d; want %d", decoded.MachineID, machineID)
89+
}
90+
if decoded.ID != id {
91+
t.Errorf("ID = %d; want %d", decoded.ID, id)
92+
}
93+
}
94+
95+
// TestConcurrency verifies that GenerateHyperflakeID is safe for concurrent use
96+
// and produces no duplicate IDs across goroutines.
97+
func TestConcurrency(t *testing.T) {
98+
const goroutines = 100
99+
const idsPerGoroutine = 100
100+
101+
config := NewHyperflakeConfig(1, 1)
102+
ids := make(chan int64, goroutines*idsPerGoroutine)
103+
104+
var wg sync.WaitGroup
105+
for i := 0; i < goroutines; i++ {
106+
wg.Add(1)
107+
go func() {
108+
defer wg.Done()
109+
for j := 0; j < idsPerGoroutine; j++ {
110+
id, err := config.GenerateHyperflakeID()
111+
if err != nil {
112+
t.Errorf("GenerateHyperflakeID() error: %v", err)
113+
return
114+
}
115+
ids <- id
116+
}
117+
}()
118+
}
119+
120+
wg.Wait()
121+
close(ids)
122+
123+
seen := make(map[int64]struct{}, goroutines*idsPerGoroutine)
124+
for id := range ids {
125+
if _, exists := seen[id]; exists {
126+
t.Errorf("duplicate ID generated: %d", id)
127+
}
128+
seen[id] = struct{}{}
129+
}
130+
}
59131

60-
idd, _ := hf.GenerateHyperflakeID()
132+
// TestClockBackwards verifies that GenerateHyperflakeID returns an error
133+
// if the clock appears to move backwards.
134+
func TestClockBackwards(t *testing.T) {
135+
config := NewHyperflakeConfig(0, 0)
136+
// Simulate a future lastTimestamp to trigger the clock-backwards guard.
137+
config.lastTimestamp = 1<<41 - 1 // max possible timestamp
61138

62-
println(idd)
139+
_, err := config.GenerateHyperflakeID()
140+
if err == nil {
141+
t.Fatal("expected clock-backwards error, got nil")
142+
}
143+
}
144+
145+
// TestCustomEpoch verifies that NewHyperflakeConfigWithEpoch uses the provided epoch
146+
// and that the decoded timestamp reflects it correctly.
147+
func TestCustomEpoch(t *testing.T) {
148+
customEpoch := int64(1_000_000_000_000) // arbitrary epoch in ms
149+
150+
config := NewHyperflakeConfigWithEpoch(1, 1, customEpoch)
151+
id, err := config.GenerateHyperflakeID()
152+
if err != nil {
153+
t.Fatalf("GenerateHyperflakeID() error: %v", err)
154+
}
155+
156+
decoded, err := config.DecodeID(id)
157+
if err != nil {
158+
t.Fatalf("DecodeID(%d) error: %v", id, err)
159+
}
160+
161+
// Timestamp field should equal TimestampSinceEpoch + customEpoch.
162+
if decoded.Timestamp != decoded.TimestampSinceEpoch+customEpoch {
163+
t.Errorf("Timestamp = %d; want TimestampSinceEpoch(%d) + epoch(%d) = %d",
164+
decoded.Timestamp, decoded.TimestampSinceEpoch, customEpoch, decoded.TimestampSinceEpoch+customEpoch)
165+
}
166+
}
167+
168+
// TestSettersGetters verifies Set/Get methods for datacenter and machine IDs.
169+
func TestSettersGetters(t *testing.T) {
170+
config := NewHyperflakeConfig(0, 0)
171+
172+
config.SetDatacenterID(15)
173+
if got := config.GetDatacenterID(); got != 15 {
174+
t.Errorf("GetDatacenterID() = %d; want 15", got)
175+
}
176+
177+
config.SetMachineID(31)
178+
if got := config.GetMachineID(); got != 31 {
179+
t.Errorf("GetMachineID() = %d; want 31", got)
180+
}
181+
182+
// Verify the updated IDs are encoded in generated IDs.
183+
id, err := config.GenerateHyperflakeID()
184+
if err != nil {
185+
t.Fatalf("GenerateHyperflakeID() error: %v", err)
186+
}
187+
decoded, err := config.DecodeID(id)
188+
if err != nil {
189+
t.Fatalf("DecodeID error: %v", err)
190+
}
191+
if decoded.DatacenterID != 15 {
192+
t.Errorf("encoded DatacenterID = %d; want 15", decoded.DatacenterID)
193+
}
194+
if decoded.MachineID != 31 {
195+
t.Errorf("encoded MachineID = %d; want 31", decoded.MachineID)
196+
}
63197
}

0 commit comments

Comments
 (0)