Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(501)

Side by Side Diff: infra_libs/ts_mon/common/test/monitors_test.py

Issue 2213143002: Add infra_libs as a bootstrap dependency. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Removed the ugly import hack Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import base64
6 import httplib2
7 import json
8 import os
9 import tempfile
10 import unittest
11
12 from googleapiclient import errors
13 import mock
14
15 from infra_libs import httplib2_utils
16 from infra_libs.ts_mon.common import interface
17 from infra_libs.ts_mon.common import monitors
18 from infra_libs.ts_mon.common import pb_to_popo
19 from infra_libs.ts_mon.common import targets
20 from infra_libs.ts_mon.protos import metrics_pb2
21 import infra_libs
22
23
24 class MonitorTest(unittest.TestCase):
25
26 def test_send(self):
27 m = monitors.Monitor()
28 metric1 = metrics_pb2.MetricsData(name='m1')
29 with self.assertRaises(NotImplementedError):
30 m.send(metric1)
31
32 class HttpsMonitorTest(unittest.TestCase):
33
34 def setUp(self):
35 super(HttpsMonitorTest, self).setUp()
36
37 def message(self, pb):
38 pb = monitors.Monitor._wrap_proto(pb)
39 return json.dumps({'resource': pb_to_popo.convert(pb) })
40
41 def _test_send(self, http):
42 mon = monitors.HttpsMonitor('endpoint', ':gce', http=http)
43 resp = mock.MagicMock(spec=httplib2.Response, status=200)
44 mon._http.request = mock.MagicMock(return_value=[resp, ""])
45
46 metric1 = metrics_pb2.MetricsData(name='m1')
47 mon.send(metric1)
48 metric2 = metrics_pb2.MetricsData(name='m2')
49 mon.send([metric1, metric2])
50 collection = metrics_pb2.MetricsCollection(data=[metric1, metric2])
51 mon.send(collection)
52
53 mon._http.request.assert_has_calls([
54 mock.call('endpoint', method='POST', body=self.message(metric1)),
55 mock.call('endpoint', method='POST',
56 body=self.message([metric1, metric2])),
57 mock.call('endpoint', method='POST', body=self.message(collection)),
58 ])
59
60 def test_default_send(self):
61 self._test_send(None)
62
63 def test_http_send(self):
64 self._test_send(httplib2.Http())
65
66 def test_instrumented_http_send(self):
67 self._test_send(httplib2_utils.InstrumentedHttp('test'))
68
69 @mock.patch('infra_libs.ts_mon.common.monitors.HttpsMonitor.'
70 '_load_credentials', autospec=True)
71 def test_send_resp_failure(self, _load_creds):
72 mon = monitors.HttpsMonitor('endpoint', '/path/to/creds.p8.json')
73 resp = mock.MagicMock(spec=httplib2.Response, status=400)
74 mon._http.request = mock.MagicMock(return_value=[resp, ""])
75
76 metric1 = metrics_pb2.MetricsData(name='m1')
77 mon.send(metric1)
78
79 mon._http.request.assert_called_once_with('endpoint', method='POST',
80 body=self.message(metric1))
81
82 @mock.patch('infra_libs.ts_mon.common.monitors.HttpsMonitor.'
83 '_load_credentials', autospec=True)
84 def test_send_http_failure(self, _load_creds):
85 mon = monitors.HttpsMonitor('endpoint', '/path/to/creds.p8.json')
86 mon._http.request = mock.MagicMock(side_effect=ValueError())
87
88 metric1 = metrics_pb2.MetricsData(name='m1')
89 mon.send(metric1)
90
91 mon._http.request.assert_called_once_with('endpoint', method='POST',
92 body=self.message(metric1))
93
94
95 class PubSubMonitorTest(unittest.TestCase):
96
97 def setUp(self):
98 super(PubSubMonitorTest, self).setUp()
99 interface.state.target = targets.TaskTarget(
100 'test_service', 'test_job', 'test_region', 'test_host')
101
102 @mock.patch('infra_libs.httplib2_utils.InstrumentedHttp', autospec=True)
103 @mock.patch('infra_libs.ts_mon.common.monitors.discovery', autospec=True)
104 @mock.patch('infra_libs.ts_mon.common.monitors.GoogleCredentials',
105 autospec=True)
106 def test_init_service_account(self, gc, discovery, instrumented_http):
107 m_open = mock.mock_open(read_data='{"type": "service_account"}')
108 creds = gc.from_stream.return_value
109 scoped_creds = creds.create_scoped.return_value
110 http_mock = instrumented_http.return_value
111 metric1 = metrics_pb2.MetricsData(name='m1')
112 with mock.patch('infra_libs.ts_mon.common.monitors.open', m_open,
113 create=True):
114 mon = monitors.PubSubMonitor('/path/to/creds.p8.json', 'myproject',
115 'mytopic')
116 mon.send(metric1)
117
118 m_open.assert_called_once_with('/path/to/creds.p8.json', 'r')
119 creds.create_scoped.assert_called_once_with(monitors.PubSubMonitor._SCOPES)
120 scoped_creds.authorize.assert_called_once_with(http_mock)
121 discovery.build.assert_called_once_with('pubsub', 'v1', http=http_mock)
122 self.assertEquals(mon._topic, 'projects/myproject/topics/mytopic')
123
124 @mock.patch('infra_libs.httplib2_utils.InstrumentedHttp', autospec=True)
125 @mock.patch('infra_libs.ts_mon.common.monitors.discovery', autospec=True)
126 @mock.patch('infra_libs.ts_mon.common.monitors.gce.AppAssertionCredentials',
127 autospec=True)
128 def test_init_gce_credential(self, aac, discovery, instrumented_http):
129 creds = aac.return_value
130 http_mock = instrumented_http.return_value
131 metric1 = metrics_pb2.MetricsData(name='m1')
132 mon = monitors.PubSubMonitor(':gce', 'myproject', 'mytopic')
133 mon.send(metric1)
134
135 aac.assert_called_once_with(monitors.PubSubMonitor._SCOPES)
136 creds.authorize.assert_called_once_with(http_mock)
137 discovery.build.assert_called_once_with('pubsub', 'v1', http=http_mock)
138 self.assertEquals(mon._topic, 'projects/myproject/topics/mytopic')
139
140 @mock.patch('infra_libs.httplib2_utils.InstrumentedHttp', autospec=True)
141 @mock.patch('infra_libs.ts_mon.common.monitors.discovery', autospec=True)
142 @mock.patch('infra_libs.ts_mon.common.monitors.Storage', autospec=True)
143 def test_init_storage(self, storage, discovery, instrumented_http):
144 storage_inst = mock.Mock()
145 storage.return_value = storage_inst
146 creds = storage_inst.get.return_value
147
148 m_open = mock.mock_open(read_data='{}')
149 http_mock = instrumented_http.return_value
150 metric1 = metrics_pb2.MetricsData(name='m1')
151 with mock.patch('infra_libs.ts_mon.common.monitors.open', m_open,
152 create=True):
153 mon = monitors.PubSubMonitor('/path/to/creds.p8.json', 'myproject',
154 'mytopic')
155 mon.send(metric1)
156
157 m_open.assert_called_once_with('/path/to/creds.p8.json', 'r')
158 storage_inst.get.assert_called_once_with()
159 creds.authorize.assert_called_once_with(http_mock)
160 discovery.build.assert_called_once_with('pubsub', 'v1', http=http_mock)
161 self.assertEquals(mon._topic, 'projects/myproject/topics/mytopic')
162
163 @mock.patch('infra_libs.ts_mon.common.monitors.PubSubMonitor.'
164 '_load_credentials', autospec=True)
165 @mock.patch('googleapiclient.discovery.build', autospec=True)
166 def test_send(self, _discovery, _load_creds):
167 mon = monitors.PubSubMonitor('/path/to/creds.p8.json', 'myproject',
168 'mytopic')
169 mon._api = mock.MagicMock()
170 topic = 'projects/myproject/topics/mytopic'
171
172 metric1 = metrics_pb2.MetricsData(name='m1')
173 mon.send(metric1)
174 metric2 = metrics_pb2.MetricsData(name='m2')
175 mon.send([metric1, metric2])
176 collection = metrics_pb2.MetricsCollection(data=[metric1, metric2])
177 mon.send(collection)
178
179 def message(pb):
180 pb = monitors.Monitor._wrap_proto(pb)
181 return {'messages': [{'data': base64.b64encode(pb.SerializeToString())}]}
182 publish = mon._api.projects.return_value.topics.return_value.publish
183 publish.assert_has_calls([
184 mock.call(topic=topic, body=message(metric1)),
185 mock.call().execute(num_retries=5),
186 mock.call(topic=topic, body=message([metric1, metric2])),
187 mock.call().execute(num_retries=5),
188 mock.call(topic=topic, body=message(collection)),
189 mock.call().execute(num_retries=5),
190 ])
191
192 @mock.patch('infra_libs.ts_mon.common.monitors.PubSubMonitor.'
193 '_load_credentials', autospec=True)
194 @mock.patch('googleapiclient.discovery.build', autospec=True)
195 def test_send_uninitialized(self, discovery, _load_creds):
196 """Test initialization retry logic, and also un-instrumented http path."""
197 discovery.side_effect = EnvironmentError() # Fail initialization.
198 mon = monitors.PubSubMonitor('/path/to/creds.p8.json', 'myproject',
199 'mytopic', use_instrumented_http=False)
200
201 metric1 = metrics_pb2.MetricsData(name='m1')
202 mon.send(metric1)
203 self.assertIsNone(mon._api)
204
205 # Another retry: initialization succeeds.
206 discovery.side_effect = None
207 mon.send(metric1)
208
209 def message(pb):
210 pb = monitors.Monitor._wrap_proto(pb)
211 return {'messages': [{'data': base64.b64encode(pb.SerializeToString())}]}
212
213 topic = 'projects/myproject/topics/mytopic'
214
215 publish = mon._api.projects.return_value.topics.return_value.publish
216 publish.assert_has_calls([
217 mock.call(topic=topic, body=message(metric1)),
218 mock.call().execute(num_retries=5),
219 ])
220
221 @mock.patch('infra_libs.ts_mon.common.monitors.PubSubMonitor.'
222 '_load_credentials', autospec=True)
223 @mock.patch('googleapiclient.discovery.build', autospec=True)
224 def test_send_fails(self, _discovery, _load_creds):
225 # Test for an occasional flake of .publish().execute().
226 mon = monitors.PubSubMonitor('/path/to/creds.p8.json', 'myproject',
227 'mytopic')
228 mon._api = mock.MagicMock()
229 topic = 'projects/myproject/topics/mytopic'
230
231 metric1 = metrics_pb2.MetricsData(name='m1')
232 mon.send(metric1)
233
234 publish = mon._api.projects.return_value.topics.return_value.publish
235 publish.side_effect = ValueError()
236
237 metric2 = metrics_pb2.MetricsData(name='m2')
238 mon.send([metric1, metric2])
239 collection = metrics_pb2.MetricsCollection(data=[metric1, metric2])
240 publish.side_effect = errors.HttpError(
241 mock.Mock(status=404, reason='test'), '')
242 mon.send(collection)
243
244 # Test that all caught exceptions are specified without errors.
245 # When multiple exceptions are specified in the 'except' clause,
246 # they are evaluated lazily, and may contain syntax errors.
247 # Throwing an uncaught exception forces all exception specs to be
248 # evaluated, catching more runtime errors.
249 publish.side_effect = Exception('uncaught')
250 with self.assertRaises(Exception):
251 mon.send(collection)
252
253 def message(pb):
254 pb = monitors.Monitor._wrap_proto(pb)
255 return {'messages': [{'data': base64.b64encode(pb.SerializeToString())}]}
256 publish.assert_has_calls([
257 mock.call(topic=topic, body=message(metric1)),
258 mock.call().execute(num_retries=5),
259 mock.call(topic=topic, body=message([metric1, metric2])),
260 mock.call(topic=topic, body=message(collection)),
261 ])
262
263
264
265 class DebugMonitorTest(unittest.TestCase):
266
267 def test_send_file(self):
268 with infra_libs.temporary_directory() as temp_dir:
269 filename = os.path.join(temp_dir, 'out')
270 m = monitors.DebugMonitor(filename)
271 metric1 = metrics_pb2.MetricsData(name='m1')
272 m.send(metric1)
273 metric2 = metrics_pb2.MetricsData(name='m2')
274 m.send([metric1, metric2])
275 collection = metrics_pb2.MetricsCollection(data=[metric1, metric2])
276 m.send(collection)
277 with open(filename) as fh:
278 output = fh.read()
279 self.assertEquals(output.count('data {\n name: "m1"\n}'), 3)
280 self.assertEquals(output.count('data {\n name: "m2"\n}'), 2)
281
282 def test_send_log(self):
283 m = monitors.DebugMonitor()
284 metric1 = metrics_pb2.MetricsData(name='m1')
285 m.send(metric1)
286 metric2 = metrics_pb2.MetricsData(name='m2')
287 m.send([metric1, metric2])
288 collection = metrics_pb2.MetricsCollection(data=[metric1, metric2])
289 m.send(collection)
290
291
292 class NullMonitorTest(unittest.TestCase):
293
294 def test_send(self):
295 m = monitors.NullMonitor()
296 metric1 = metrics_pb2.MetricsData(name='m1')
297 m.send(metric1)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698