-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtest_test.go
130 lines (114 loc) · 2.3 KB
/
test_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
package hashring
import (
"bytes"
"encoding/binary"
"fmt"
"hash"
"strconv"
"strings"
"testing"
"github.com/cespare/xxhash/v2"
)
type digestArgs struct {
item string
n int
suffix [2]int
}
func (d digestArgs) String() string {
var sb strings.Builder
fmt.Fprintf(&sb, "%#q", d.item)
sb.WriteByte('[')
for i := 0; i < d.n; i++ {
if i > 0 {
sb.WriteByte(',')
}
sb.WriteString(strconv.Itoa(d.suffix[i]))
}
sb.WriteByte(']')
return sb.String()
}
func digestCall(s string, suffix ...int) digestArgs {
args := digestArgs{item: s}
if len(suffix) > 2 {
panic(fmt.Sprintf(
"digest hook: too many suffix ints for %#q: %v",
s, suffix,
))
}
args.n = copy(args.suffix[:], suffix)
return args
}
func setupDigest(t *testing.T, r *Ring, values map[digestArgs]uint64) {
r.Hash = func() hash.Hash64 {
return &hash64{
t: t,
values: values,
}
}
}
type hash64 struct {
t testing.TB
values map[digestArgs]uint64
buf bytes.Buffer
}
func (h *hash64) Write(p []byte) (int, error) {
return h.buf.Write(p)
}
func (h *hash64) Sum(b []byte) []byte {
panic("hashring: hash Sum() must not be called")
}
func (h *hash64) Reset() {
h.buf.Reset()
}
func (h *hash64) Size() int {
return 8
}
func (h *hash64) BlockSize() int {
return 1
}
func (h *hash64) Sum64() uint64 {
item, suff := splitSuffix(h.buf.Bytes())
call := digestCall(string(item), suff...)
v, has := h.values[call]
if has {
h.t.Logf("using digest value for call %s: %d", call, v)
return v
}
return xxDigest(h.buf.Bytes())
}
func xxDigest(p []byte) uint64 {
h := xxhash.New()
_, err := h.Write(p)
if err != nil {
panic(err)
}
return h.Sum64()
}
// splitSuffix splits given bytes slice by the item bytes and its suffix,
// produced by a ring.
//
// NOTE: it's assumed that item bytes are no longer than 2*intSize (intSize is
// 4 or 8 bytes depending on arch).
func splitSuffix(bts []byte) (item []byte, ints []int) {
n := len(bts)
s := 2 * intSize
if n <= s {
// No suffix added.
return bts, nil
}
suf := bts[n-s:]
return bts[:s], []int{
decodeInt(suf[0*intSize:]),
decodeInt(suf[1*intSize:]),
}
}
func decodeInt(src []byte) int {
switch intSize {
case 4:
return int(binary.LittleEndian.Uint32(src))
case 8:
return int(binary.LittleEndian.Uint64(src))
default:
panic("unexpected int size")
}
}