Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 187 lines (160 sloc) 6.951 kB
1fd81e9 Add the tallier service: a multi-process statsd replacement.
Logan Hanks authored
1 #!/usr/bin/env python
2
3 import collections
4 import ConfigParser
5 import time
6 import unittest
7
8 import tallier
9 import testing
10
11 def build_config(**sections):
12 config = ConfigParser.RawConfigParser()
13 for section, data in sections.iteritems():
14 config.add_section(section)
15 for name, value in data.iteritems():
16 config.set(section, name, value)
17 return config
18
19 class MasterTest(unittest.TestCase):
20 def test_from_config(self):
21 # underspecified
22 harold = dict(host='localhost', port=8888, secret='secret')
23 graphite = dict(graphite_addr='localhost:9999')
24 t = dict(port=7777, num_workers=1)
25 config = build_config(harold=harold, graphite=graphite, tallier=t)
26 master = tallier.Master.from_config(config, harold='stub')
27 self.assertEquals('', master.iface)
28 self.assertEquals(7777, master.port)
29 self.assertEquals(1, master.num_workers)
30 self.assertEquals(10.0, master.flush_interval)
31 self.assertEquals('localhost', master.graphite_host)
32 self.assertEquals(9999, master.graphite_port)
33 self.assertTrue(master.harold is not None)
34
35 # fully specified
36 t.update(flush_interval=5.0, interface='localhost',
37 enable_heartbeat='true')
38 config = build_config(harold=harold, graphite=graphite, tallier=t)
39 master = tallier.Master.from_config(config, harold='stub')
40 self.assertEquals(5.0, master.flush_interval)
41 self.assertEquals('localhost', master.iface)
42 self.assertTrue(master.harold is not None)
43
44 # disable heartbeats
45 t.update(enable_heartbeat='false')
46 config = build_config(harold=harold, graphite=graphite, tallier=t)
47 master = tallier.Master.from_config(config, harold='stub')
48 self.assertTrue(master.harold is None)
49
50 @testing.stub(time, 'time')
51 def test_build_graphite_report(self):
52 now = 1000
53 time.time = lambda: now
54 master = tallier.Master('', 0, 1, flush_interval=2.0)
55 master.last_flush_time = now - 2
56 master.num_stats = 0
57
58 agg_counters = dict(a=1, b=2, c=3)
59 agg_timers = dict(
60 a=range(100), # mean=49.5
61 )
62
63 m = lambda k, v: '%s %f %d' % (k, v, now)
64
65 msgs = list(master._build_graphite_report(agg_counters, agg_timers))
66 self.assertEquals(
67 sorted([
68 m('stats.a', 0.5),
69 m('stats_counts.a', 1),
70 m('stats.b', 1),
71 m('stats_counts.b', 2),
72 m('stats.c', 1.5),
73 m('stats_counts.c', 3),
74 m('stats.timers.a.lower', 0),
75 m('stats.timers.a.upper', 99),
76 m('stats.timers.a.upper_90', 90),
77 m('stats.timers.a.mean', 49.5),
78 m('stats.timers.a.count', 100),
79 m('stats.timers.a.rate', 50),
80 m('stats.tallier.num_workers', 1),
81 m('stats.tallier.num_stats', 4),
82 ]), sorted(msgs))
83
84 def test_flush(self):
85 child_reports = [
86 ({'a': 1}, {'t1': [1, 2, 3]}),
87 ({'b': 2}, {'t2': [2, 3, 4]}),
88 ({'a': 3, 'b': 4}, {'t1': [5, 6], 't2': [6, 7]}),
89 ]
90 master = tallier.Master('', 0, 1)
91 master._command_all = lambda cmd: child_reports
92 master._build_graphite_report = lambda x, y: (
93 x, dict((k, list(sorted(v))) for k, v in y.iteritems()))
94 master._send_to_graphite = lambda x: x
95
96 agg_counters, agg_timers = master._flush()
97 self.assertEquals(
98 {'a': 4, 'b': 6, 'tallier.messages.total': 0}, agg_counters)
99 self.assertEquals(
100 {'t1': [1, 2, 3, 5, 6], 't2': [2, 3, 4, 6, 7]}, agg_timers)
101
102 class ListenerTest(unittest.TestCase):
103 def test_handle_sample(self):
104 listener = tallier.Listener(0, None)
105 listener.current_samples = (collections.defaultdict(float), {})
106
107 s = tallier.Sample(
108 key='key', value=1.0, value_type=tallier.Sample.COUNTER,
109 sample_rate=0.5)
110 listener._handle_sample(s)
111 self.assertEquals(2.0, listener.current_samples[0]['key'])
112
113 s.sample_rate = 1.0
114 listener._handle_sample(s)
115 self.assertEquals(3.0, listener.current_samples[0]['key'])
116
117 s.value_type = tallier.Sample.TIMER
118 for i in xrange(3):
119 s.value = i
120 listener._handle_sample(s)
121 self.assertEquals(range(3), listener.current_samples[1]['key'])
122
123 def test_flush(self):
124 listener = tallier.Listener(0, None)
125 listener.message_count = 0
126 listener.last_message_count = 0
127 listener.current_samples = (collections.defaultdict(float), {})
128 listener._handle_datagram('key:1|c:2|c:3|c:4|ms:5|ms:6|ms')
129 expected_data = (
130 {'key': 6},
131 {'key': [4, 5, 6]})
132 self.assertEquals(expected_data, listener.current_samples)
133 expected_data[0]['tallier.messages.child_0'] = 1
134 self.assertEquals(expected_data, listener.flush())
135 self.assertEquals(({}, {}), listener.current_samples)
136
137 class SampleTest(unittest.TestCase):
138 def test_normalize_key(self):
139 n = tallier.Sample._normalize_key
140 self.assertEquals('test', n('test'))
141 self.assertEquals('test_1', n('test_1'))
142 self.assertEquals('test_1-2', n('test 1\\2'))
143 self.assertEquals('test1-2', n('[()@test#@&$^@&#*^1-2'))
144
145 def test_parse_part(self):
146 p = tallier.Sample._parse_part
147 k = 'key'
148 self.assertRaises(ValueError, p, k, '123')
149
150 s = p(k, '123|c')
151 self.assertEquals(k, s.key)
152 self.assertEquals(123.0, s.value)
153 self.assertEquals(tallier.Sample.COUNTER, s.value_type)
154 self.assertEquals(1.0, s.sample_rate)
155
156 s = p(k, '123|c@0.5')
157 self.assertEquals(k, s.key)
158 self.assertEquals(123.0, s.value)
159 self.assertEquals(tallier.Sample.COUNTER, s.value_type)
160 self.assertEquals(0.5, s.sample_rate)
161
162 s = p(k, '123.45|ms')
163 self.assertEquals(k, s.key)
164 self.assertEquals(123.45, s.value)
165 self.assertEquals(tallier.Sample.TIMER, s.value_type)
166 self.assertEquals(1.0, s.sample_rate)
167
168 def test_parse(self):
169 self.assertEquals([], tallier.Sample.parse('a:b:c'))
170
171 (s,) = tallier.Sample.parse('key:123.45|ms@0.5')
172 self.assertEquals('key', s.key)
173 self.assertEquals(123.45, s.value)
174 self.assertEquals(tallier.Sample.TIMER, s.value_type)
175 self.assertEquals(0.5, s.sample_rate)
176
177 ss = tallier.Sample.parse('key1:1|c:2|c:3|c')
178 self.assertEquals(3, len(ss))
179 self.assertEquals('key1', ss[0].key)
180 self.assertEquals('key1', ss[1].key)
181 self.assertEquals(1, ss[0].value)
182 self.assertEquals(2, ss[1].value)
183 self.assertEquals(3, ss[2].value)
184
185 if __name__ == '__main__':
186 unittest.main()
Something went wrong with that request. Please try again.