0 | 0 |
package statsd
|
1 | |
|
2 | |
// In package metrics so we can stub tick.
|
3 | 1 |
|
4 | 2 |
import (
|
5 | 3 |
"bytes"
|
6 | 4 |
"fmt"
|
7 | |
"runtime"
|
8 | 5 |
"strings"
|
|
6 |
"sync"
|
9 | 7 |
"testing"
|
10 | 8 |
"time"
|
11 | 9 |
)
|
12 | 10 |
|
13 | 11 |
func TestCounter(t *testing.T) {
|
14 | |
ch := make(chan time.Time)
|
15 | |
tick = func(time.Duration) <-chan time.Time { return ch }
|
16 | |
defer func() { tick = time.Tick }()
|
17 | |
|
18 | |
buf := &bytes.Buffer{}
|
19 | |
c := NewCounter(buf, "test_statsd_counter", time.Second)
|
|
12 |
buf := &syncbuf{buf: &bytes.Buffer{}}
|
|
13 |
reportc := make(chan time.Time)
|
|
14 |
c := NewCounterTick(buf, "test_statsd_counter", reportc)
|
20 | 15 |
|
21 | 16 |
c.Add(1)
|
22 | 17 |
c.Add(2)
|
23 | |
ch <- time.Now()
|
24 | 18 |
|
25 | |
for i := 0; i < 10 && buf.Len() == 0; i++ {
|
26 | |
time.Sleep(time.Millisecond)
|
27 | |
}
|
28 | |
|
29 | |
if want, have := "test_statsd_counter:1|c\ntest_statsd_counter:2|c\n", buf.String(); want != have {
|
30 | |
t.Errorf("want %q, have %q", want, have)
|
31 | |
}
|
|
19 |
want, have := "test_statsd_counter:1|c\ntest_statsd_counter:2|c\n", ""
|
|
20 |
by(t, 100*time.Millisecond, func() bool {
|
|
21 |
have = buf.String()
|
|
22 |
return want == have
|
|
23 |
}, func() {
|
|
24 |
reportc <- time.Now()
|
|
25 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
32 | 26 |
}
|
33 | 27 |
|
34 | 28 |
func TestGauge(t *testing.T) {
|
35 | |
ch := make(chan time.Time)
|
36 | |
tick = func(time.Duration) <-chan time.Time { return ch }
|
37 | |
defer func() { tick = time.Tick }()
|
38 | |
|
39 | |
buf := &bytes.Buffer{}
|
40 | |
g := NewGauge(buf, "test_statsd_gauge", time.Second)
|
|
29 |
buf := &syncbuf{buf: &bytes.Buffer{}}
|
|
30 |
reportc := make(chan time.Time)
|
|
31 |
g := NewGaugeTick(buf, "test_statsd_gauge", reportc)
|
41 | 32 |
|
42 | 33 |
delta := 1.0
|
43 | |
g.Add(delta) // send command
|
44 | |
runtime.Gosched() // yield to buffer write
|
45 | |
ch <- time.Now() // signal flush
|
46 | |
runtime.Gosched() // yield to flush
|
47 | |
if want, have := fmt.Sprintf("test_statsd_gauge:+%f|g\n", delta), buf.String(); want != have {
|
48 | |
t.Errorf("want %q, have %q", want, have)
|
49 | |
}
|
|
34 |
g.Add(delta)
|
|
35 |
|
|
36 |
want, have := fmt.Sprintf("test_statsd_gauge:+%f|g\n", delta), ""
|
|
37 |
by(t, 100*time.Millisecond, func() bool {
|
|
38 |
have = buf.String()
|
|
39 |
return want == have
|
|
40 |
}, func() {
|
|
41 |
reportc <- time.Now()
|
|
42 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
50 | 43 |
|
51 | 44 |
buf.Reset()
|
52 | |
|
53 | 45 |
delta = -2.0
|
54 | 46 |
g.Add(delta)
|
55 | |
runtime.Gosched()
|
56 | |
ch <- time.Now()
|
57 | |
runtime.Gosched()
|
58 | |
if want, have := fmt.Sprintf("test_statsd_gauge:%f|g\n", delta), buf.String(); want != have {
|
59 | |
t.Errorf("want %q, have %q", want, have)
|
60 | |
}
|
|
47 |
|
|
48 |
want, have = fmt.Sprintf("test_statsd_gauge:%f|g\n", delta), ""
|
|
49 |
by(t, 100*time.Millisecond, func() bool {
|
|
50 |
have = buf.String()
|
|
51 |
return want == have
|
|
52 |
}, func() {
|
|
53 |
reportc <- time.Now()
|
|
54 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
61 | 55 |
|
62 | 56 |
buf.Reset()
|
63 | |
|
64 | 57 |
value := 3.0
|
65 | 58 |
g.Set(value)
|
66 | |
runtime.Gosched()
|
67 | |
ch <- time.Now()
|
68 | |
runtime.Gosched()
|
69 | |
if want, have := fmt.Sprintf("test_statsd_gauge:%f|g\n", value), buf.String(); want != have {
|
70 | |
t.Errorf("want %q, have %q", want, have)
|
71 | |
}
|
|
59 |
|
|
60 |
want, have = fmt.Sprintf("test_statsd_gauge:%f|g\n", value), ""
|
|
61 |
by(t, 100*time.Millisecond, func() bool {
|
|
62 |
have = buf.String()
|
|
63 |
return want == have
|
|
64 |
}, func() {
|
|
65 |
reportc <- time.Now()
|
|
66 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
72 | 67 |
}
|
73 | 68 |
|
74 | 69 |
func TestCallbackGauge(t *testing.T) {
|
75 | |
ch := make(chan time.Time)
|
76 | |
tick = func(time.Duration) <-chan time.Time { return ch }
|
77 | |
defer func() { tick = time.Tick }()
|
78 | |
|
79 | |
buf := &bytes.Buffer{}
|
|
70 |
buf := &syncbuf{buf: &bytes.Buffer{}}
|
|
71 |
reportc, scrapec := make(chan time.Time), make(chan time.Time)
|
80 | 72 |
value := 55.55
|
81 | 73 |
cb := func() float64 { return value }
|
82 | |
NewCallbackGauge(buf, "test_statsd_callback_gauge", time.Second, time.Nanosecond, cb)
|
|
74 |
NewCallbackGaugeTick(buf, "test_statsd_callback_gauge", reportc, scrapec, cb)
|
83 | 75 |
|
84 | |
ch <- time.Now() // signal emitter
|
85 | |
runtime.Gosched() // yield to emitter
|
86 | |
ch <- time.Now() // signal flush
|
87 | |
runtime.Gosched() // yield to flush
|
|
76 |
scrapec <- time.Now()
|
|
77 |
reportc <- time.Now()
|
88 | 78 |
|
89 | 79 |
// Travis is annoying
|
90 | |
check := func() bool { return buf.String() != "" }
|
91 | |
execute := func() { ch <- time.Now(); runtime.Gosched(); time.Sleep(5 * time.Millisecond) }
|
92 | |
by(t, time.Second, check, execute, "buffer never got write+flush")
|
|
80 |
by(t, time.Second, func() bool {
|
|
81 |
return buf.String() != ""
|
|
82 |
}, func() {
|
|
83 |
reportc <- time.Now()
|
|
84 |
}, "buffer never got write+flush")
|
93 | 85 |
|
94 | |
if want, have := fmt.Sprintf("test_statsd_callback_gauge:%f|g\n", value), buf.String(); !strings.HasPrefix(have, want) {
|
95 | |
t.Errorf("want %q, have %q", want, have)
|
96 | |
}
|
|
86 |
want, have := fmt.Sprintf("test_statsd_callback_gauge:%f|g\n", value), ""
|
|
87 |
by(t, 100*time.Millisecond, func() bool {
|
|
88 |
have = buf.String()
|
|
89 |
return strings.HasPrefix(have, want) // HasPrefix because we might get multiple writes
|
|
90 |
}, func() {
|
|
91 |
reportc <- time.Now()
|
|
92 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
97 | 93 |
}
|
98 | 94 |
|
99 | 95 |
func TestHistogram(t *testing.T) {
|
100 | |
ch := make(chan time.Time)
|
101 | |
tick = func(time.Duration) <-chan time.Time { return ch }
|
102 | |
defer func() { tick = time.Tick }()
|
103 | |
|
104 | |
buf := &bytes.Buffer{}
|
105 | |
h := NewHistogram(buf, "test_statsd_histogram", time.Second)
|
|
96 |
buf := &syncbuf{buf: &bytes.Buffer{}}
|
|
97 |
reportc := make(chan time.Time)
|
|
98 |
h := NewHistogramTick(buf, "test_statsd_histogram", reportc)
|
106 | 99 |
|
107 | 100 |
h.Observe(123)
|
108 | 101 |
|
109 | |
runtime.Gosched()
|
110 | |
ch <- time.Now()
|
111 | |
runtime.Gosched()
|
112 | |
if want, have := "test_statsd_histogram:123|ms\n", buf.String(); want != have {
|
113 | |
t.Errorf("want %q, have %q", want, have)
|
114 | |
}
|
|
102 |
want, have := "test_statsd_histogram:123|ms\n", ""
|
|
103 |
by(t, 100*time.Millisecond, func() bool {
|
|
104 |
have = buf.String()
|
|
105 |
return want == have
|
|
106 |
}, func() {
|
|
107 |
reportc <- time.Now()
|
|
108 |
}, fmt.Sprintf("want %q, have %q", want, have))
|
115 | 109 |
}
|
116 | 110 |
|
117 | 111 |
func by(t *testing.T, d time.Duration, check func() bool, execute func(), msg string) {
|
|
123 | 117 |
execute()
|
124 | 118 |
}
|
125 | 119 |
}
|
|
120 |
|
|
121 |
type syncbuf struct {
|
|
122 |
mtx sync.Mutex
|
|
123 |
buf *bytes.Buffer
|
|
124 |
}
|
|
125 |
|
|
126 |
func (s *syncbuf) Write(p []byte) (int, error) {
|
|
127 |
s.mtx.Lock()
|
|
128 |
defer s.mtx.Unlock()
|
|
129 |
return s.buf.Write(p)
|
|
130 |
}
|
|
131 |
|
|
132 |
func (s *syncbuf) String() string {
|
|
133 |
s.mtx.Lock()
|
|
134 |
defer s.mtx.Unlock()
|
|
135 |
return s.buf.String()
|
|
136 |
}
|
|
137 |
|
|
138 |
func (s *syncbuf) Reset() {
|
|
139 |
s.mtx.Lock()
|
|
140 |
defer s.mtx.Unlock()
|
|
141 |
s.buf.Reset()
|
|
142 |
}
|