-
Notifications
You must be signed in to change notification settings - Fork 21
/
generator_test.go
146 lines (115 loc) · 2.84 KB
/
generator_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package katsubushi
import (
"sync/atomic"
"testing"
"time"
)
var nextWorkerID uint32
func getNextWorkerID() uint {
return uint(atomic.AddUint32(&nextWorkerID, 1))
}
func TestInvalidWorkerID(t *testing.T) {
// workerIDMask = 10bits = 0~1023
if _, err := NewGenerator(1023); err != nil {
t.Errorf("unexpected error: %s", err)
}
if _, err := NewGenerator(1024); err != ErrInvalidWorkerID {
t.Errorf("invalid error for overranged workerID: %s", err)
}
}
func TestUniqueWorkerID(t *testing.T) {
mayBeDup := getNextWorkerID()
_, err := NewGenerator(mayBeDup)
if err != nil {
t.Fatalf("failed to create first generator: %s", err)
}
_, err = NewGenerator(getNextWorkerID())
if err != nil {
t.Fatalf("failed to create second generator: %s", err)
}
g, _ := NewGenerator(mayBeDup) // duplicate!!
if g != nil {
t.Fatalf("worker ID must be unique")
}
}
func TestGenerateAnID(t *testing.T) {
workerID := getNextWorkerID()
g, err := NewGenerator(workerID)
if err != nil {
t.Fatalf("failed to create new generator: %s", err)
}
var id uint64
now := time.Now()
t.Log("generate")
{
ident, err := g.NextID()
if err != nil {
t.Fatalf("failed to generate id: %s", err)
}
if id < 0 {
t.Error("invalid id")
}
id = ident
}
t.Logf("id = %d", id)
t.Log("restore timestamp")
{
timestampSince := uint64(Epoch.UnixNano()) / uint64(time.Millisecond)
ts := (id & 0x7FFFFFFFFFC00000 >> (WorkerIDBits + SequenceBits)) + timestampSince
nowMsec := uint64(now.UnixNano()) / uint64(time.Millisecond)
// To avoid failure would cause by timestamp on execution.
if nowMsec != ts && ts != nowMsec+1 {
t.Errorf("failed to restore timestamp: %d", ts)
}
}
t.Log("restore worker ID")
{
wid := uint(id & 0x3FF000 >> SequenceBits)
if wid != workerID {
t.Errorf("failed to restore worker ID: %d", wid)
}
}
}
func TestGenerateSomeIDs(t *testing.T) {
g, _ := NewGenerator(getNextWorkerID())
ids := []uint64{}
for i := 0; i < 1000; i++ {
id, err := g.NextID()
if err != nil {
t.Fatalf("failed to generate id: %s", err)
}
for _, otherID := range ids {
if otherID == id {
t.Fatal("id duplicated!!")
}
}
if l := len(ids); 0 < l && id < ids[l-1] {
t.Fatal("generated smaller id!!")
}
ids = append(ids, id)
}
t.Logf("%d ids are tested", len(ids))
}
func TestClockRollback(t *testing.T) {
g, _ := NewGenerator(getNextWorkerID())
_, err := g.NextID()
if err != nil {
t.Fatalf("failed to generate id: %s", err)
}
// サーバーの時計が巻き戻った想定
setNowFunc(func() time.Time {
return time.Now().Add(-10 * time.Minute)
})
_, err = g.NextID()
if err == nil {
t.Fatalf("when server clock rollback, generater must return error")
}
t.Log(err)
}
func BenchmarkGenerateID(b *testing.B) {
g, _ := NewGenerator(getNextWorkerID())
b.ResetTimer()
for i := 0; i < b.N; i++ {
g.NextID()
}
}