-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsketch_test.go
103 lines (87 loc) · 2.36 KB
/
sketch_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
package sketchy
import (
"encoding/binary"
"fmt"
"math"
"math/rand"
"net"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func shouldEqual(actual interface{}, expected ...interface{}) string {
actualCounts := actual.(map[string]uint64)
expectedCounts := expected[0].(map[string]uint64)
epsilon := expected[1].(float64)
delta := expected[2].(float64)
tot := uint64(0)
for _, v := range expectedCounts {
tot += v
}
errs := 0
for k, v := range expectedCounts {
diff := math.Abs(float64(v) - float64(actualCounts[k]))
if diff > math.Ceil(epsilon*float64(tot)) {
Printf("error of %f (%f)\n", diff-math.Ceil(epsilon*float64(actualCounts[k])),
float64(diff)/float64(tot))
errs++
}
}
if max := delta * float64(len(expectedCounts)); float64(errs) > max {
return fmt.Sprintf("more than %d counts (%d) were outside of epsilon range", int(max), errs)
}
return ""
}
func TestSketch(t *testing.T) {
counts := map[string]uint64{
"one": 1,
"two": 2,
"three": 3,
"a lot": 42,
"a bunch": 512,
"tons": 1024,
"wow much spam": 64000,
}
for len(counts) < 500 {
bytes := make([]byte, 4)
binary.BigEndian.PutUint32(bytes, rand.Uint32())
ip := net.IP(bytes).String()
if _, ok := counts[ip]; !ok {
counts[ip] = uint64(len(counts))
}
}
tot := uint64(0)
for _, v := range counts {
tot += v
}
events := make([]string, 0, tot)
for k, v := range counts {
for i := uint64(0); i < v; i++ {
events = append(events, k)
}
}
latest := map[string]uint64{}
bucket := NewSketch(0, 0)
for _, i := range rand.Perm(len(events)) {
latest[events[i]] = bucket.Count([]byte(events[i]), 1)
}
Convey("Counts should be roughly accurate", t, func() {
So(latest, shouldEqual, counts, 0.001, 0.01)
})
Convey("Gob encoding/decoding should result in the same counts", t, func() {
encoding, err := encode(bucket)
So(err, ShouldBeNil)
Printf("encoding is %d bytes\n", len(encoding))
clone := NewSketch(0, 0)
So(decode(clone, encoding), ShouldBeNil)
cloneCounts := map[string]uint64{}
for k, v := range counts {
cloneCounts[k] = v + 1
latest[k] = clone.Count([]byte(k), 1)
}
So(latest, shouldEqual, cloneCounts, 0.001, 0.01)
})
Convey("Count returns the updated value", t, func() {
bucket := NewSketch(0, 0)
So(bucket.Count([]byte("key"), 10), ShouldEqual, 10)
})
}