-
Notifications
You must be signed in to change notification settings - Fork 5
/
partition_test.go
117 lines (94 loc) · 2.71 KB
/
partition_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
package sno
import (
"sync/atomic"
"testing"
)
func TestPartition_Public_Conversions(t *testing.T) {
t.Run("AsUint16", func(t *testing.T) {
src := Partition{255, 255}
expected := uint16(MaxPartition)
actual := src.AsUint16()
if actual != expected {
t.Errorf("expected [%d], got [%d]", expected, actual)
}
})
t.Run("PutUint16", func(t *testing.T) {
expected := Partition{255, 255}
actual := Partition{}
actual.PutUint16(MaxPartition)
if actual != expected {
t.Errorf("expected [%s], got [%s]", expected, actual)
}
})
}
func TestPartition_Internal_Conversions(t *testing.T) {
public := Partition{255, 255}
internal := uint32(MaxPartition) << 16
t.Run("to-internal", func(t *testing.T) {
expected := internal
actual := partitionToInternalRepr(public)
if actual != expected {
t.Errorf("expected [%d], got [%d]", expected, actual)
}
})
t.Run("to-public", func(t *testing.T) {
expected := public
actual := partitionToPublicRepr(internal)
if actual != expected {
t.Errorf("expected [%d], got [%d]", expected, actual)
}
})
}
func TestPartition_Internal_Generation(t *testing.T) {
t.Run("monotonic-increments", func(t *testing.T) {
// Reset global count (leaving seed as is).
atomic.StoreUint32(&partitions, 0)
var prevPartition = uint32(seed) << 16
for i := 0; i < 100; i++ {
p, err := genPartition()
if err != nil {
t.Fatal(err)
}
// Note: genPartition() shifts to make space for the sequence,
// so we can't simply check for an increment of 1 within the resulting
// uint32. The below is a tiny bit faster than converting back
// to an uint16.
if p-prevPartition != 1<<16 {
t.Errorf("expected [%d], got [%d]", prevPartition+1<<16, p)
break
}
prevPartition = p
}
})
t.Run("pool-exhaustion", func(t *testing.T) {
// Reset global count (leaving seed as is).
atomic.StoreUint32(&partitions, 0)
for i := 0; i < 2*MaxPartition; i++ {
_, err := genPartition()
if err != nil {
verr, ok := err.(*PartitionPoolExhaustedError)
if !ok {
t.Fatalf("expected error type [%T], got [%T]", &PartitionPoolExhaustedError{}, err)
return
}
if i < MaxPartition {
t.Fatalf("expected errors no sooner than after [%d] iterations, got to [%d]", MaxPartition, i)
return
}
errMsgActual := verr.Error()
errMsgExpected := errPartitionPoolExhaustedMsg
if errMsgActual != errMsgExpected {
t.Fatalf("expected error msg [%s], got [%s]", errMsgExpected, errMsgActual)
}
}
if i >= MaxPartition {
if err == nil {
t.Fatalf("expected constant errors after [%d] iterations, got no error at [%d]", MaxPartition, i)
return
}
}
}
})
// Clean up.
atomic.StoreUint32(&partitions, 0)
}