OLD | NEW |
| (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 argparse | |
6 import json | |
7 import os | |
8 import requests | |
9 import tempfile | |
10 import unittest | |
11 | |
12 import mock | |
13 | |
14 from testing_support import auto_stub | |
15 | |
16 from infra_libs.ts_mon import config | |
17 from infra_libs.ts_mon.common import interface | |
18 from infra_libs.ts_mon.common import standard_metrics | |
19 from infra_libs.ts_mon.common import monitors | |
20 from infra_libs.ts_mon.common import targets | |
21 from infra_libs.ts_mon.common.test import stubs | |
22 import infra_libs | |
23 | |
24 | |
25 DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') | |
26 | |
27 | |
28 class GlobalsTest(auto_stub.TestCase): | |
29 | |
30 def setUp(self): | |
31 super(GlobalsTest, self).setUp() | |
32 self.mock(config, 'load_machine_config', lambda x: {}) | |
33 | |
34 def tearDown(self): | |
35 # It's important to call close() before un-setting the mock state object, | |
36 # because any FlushThread started by the test is stored in that mock state | |
37 # and needs to be stopped before running any other tests. | |
38 interface.close() | |
39 # This should probably live in interface.close() | |
40 interface.state = interface.State() | |
41 super(GlobalsTest, self).tearDown() | |
42 | |
43 @mock.patch('requests.get', autospec=True) | |
44 @mock.patch('socket.getfqdn', autospec=True) | |
45 def test_pubsub_monitor_args(self, fake_fqdn, fake_get): | |
46 fake_fqdn.return_value = 'slave1-a1.reg.tld' | |
47 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
48 p = argparse.ArgumentParser() | |
49 config.add_argparse_options(p) | |
50 args = p.parse_args([ | |
51 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
52 '--ts-mon-endpoint', 'pubsub://invalid-project/invalid-topic']) | |
53 | |
54 config.process_argparse_options(args) | |
55 | |
56 self.assertIsInstance(interface.state.global_monitor, | |
57 monitors.PubSubMonitor) | |
58 | |
59 self.assertIsInstance(interface.state.target, targets.DeviceTarget) | |
60 self.assertEquals(interface.state.target.hostname, 'slave1-a1') | |
61 self.assertEquals(interface.state.target.region, 'reg') | |
62 self.assertEquals(args.ts_mon_flush, 'auto') | |
63 self.assertIsNotNone(interface.state.flush_thread) | |
64 self.assertTrue(standard_metrics.up.get()) | |
65 | |
66 @mock.patch('requests.get', autospec=True) | |
67 @mock.patch('socket.getfqdn', autospec=True) | |
68 @mock.patch('infra_libs.ts_mon.common.monitors.HttpsMonitor.' | |
69 '_load_credentials', autospec=True) | |
70 def test_https_monitor_args(self, _load_creds, fake_fqdn, fake_get): | |
71 print [_load_creds, fake_fqdn, fake_get] | |
72 fake_fqdn.return_value = 'slave1-a1.reg.tld' | |
73 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
74 p = argparse.ArgumentParser() | |
75 config.add_argparse_options(p) | |
76 args = p.parse_args([ | |
77 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
78 '--ts-mon-endpoint', 'https://test/random:insert']) | |
79 | |
80 config.process_argparse_options(args) | |
81 | |
82 self.assertIsInstance(interface.state.global_monitor, | |
83 monitors.HttpsMonitor) | |
84 | |
85 self.assertIsInstance(interface.state.target, targets.DeviceTarget) | |
86 self.assertEquals(interface.state.target.hostname, 'slave1-a1') | |
87 self.assertEquals(interface.state.target.region, 'reg') | |
88 self.assertEquals(args.ts_mon_flush, 'auto') | |
89 self.assertIsNotNone(interface.state.flush_thread) | |
90 self.assertTrue(standard_metrics.up.get()) | |
91 | |
92 @mock.patch('requests.get', autospec=True) | |
93 @mock.patch('socket.getfqdn', autospec=True) | |
94 def test_default_target_uppercase_fqdn(self, fake_fqdn, fake_get): | |
95 fake_fqdn.return_value = 'SLAVE1-A1.REG.TLD' | |
96 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
97 p = argparse.ArgumentParser() | |
98 config.add_argparse_options(p) | |
99 args = p.parse_args([ | |
100 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
101 '--ts-mon-endpoint', 'unsupported://www.googleapis.com/some/api']) | |
102 config.process_argparse_options(args) | |
103 self.assertIsInstance(interface.state.target, targets.DeviceTarget) | |
104 self.assertEquals(interface.state.target.hostname, 'slave1-a1') | |
105 self.assertEquals(interface.state.target.region, 'reg') | |
106 | |
107 @mock.patch('requests.get', autospec=True) | |
108 @mock.patch('socket.getfqdn', autospec=True) | |
109 def test_default_target_fqdn_without_domain(self, fake_fqdn, fake_get): | |
110 fake_fqdn.return_value = 'SLAVE1-A1' | |
111 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
112 p = argparse.ArgumentParser() | |
113 config.add_argparse_options(p) | |
114 args = p.parse_args([ | |
115 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
116 '--ts-mon-endpoint', 'unsupported://www.googleapis.com/some/api']) | |
117 config.process_argparse_options(args) | |
118 self.assertIsInstance(interface.state.target, targets.DeviceTarget) | |
119 self.assertEquals(interface.state.target.hostname, 'slave1-a1') | |
120 self.assertEquals(interface.state.target.region, '') | |
121 | |
122 @mock.patch('requests.get', autospec=True) | |
123 @mock.patch('socket.getfqdn', autospec=True) | |
124 def test_fallback_monitor_args(self, fake_fqdn, fake_get): | |
125 fake_fqdn.return_value = 'foo' | |
126 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
127 p = argparse.ArgumentParser() | |
128 config.add_argparse_options(p) | |
129 args = p.parse_args([ | |
130 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
131 '--ts-mon-endpoint', 'unsupported://www.googleapis.com/some/api']) | |
132 config.process_argparse_options(args) | |
133 | |
134 self.assertIsInstance(interface.state.global_monitor, | |
135 monitors.NullMonitor) | |
136 | |
137 @mock.patch('requests.get', autospec=True) | |
138 @mock.patch('socket.getfqdn', autospec=True) | |
139 def test_explicit_disable_args(self, fake_fqdn, fake_get): | |
140 fake_fqdn.return_value = 'foo' | |
141 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
142 p = argparse.ArgumentParser() | |
143 config.add_argparse_options(p) | |
144 args = p.parse_args([ | |
145 '--ts-mon-credentials', '/path/to/creds.p8.json', | |
146 '--ts-mon-endpoint', 'none']) | |
147 config.process_argparse_options(args) | |
148 | |
149 self.assertIsInstance(interface.state.global_monitor, | |
150 monitors.NullMonitor) | |
151 | |
152 @mock.patch('requests.get', autospec=True) | |
153 @mock.patch('socket.getfqdn', autospec=True) | |
154 def test_manual_flush(self, fake_fqdn, fake_get): | |
155 fake_fqdn.return_value = 'foo' | |
156 fake_get.return_value.side_effect = requests.exceptions.ConnectionError | |
157 p = argparse.ArgumentParser() | |
158 config.add_argparse_options(p) | |
159 args = p.parse_args(['--ts-mon-flush', 'manual']) | |
160 | |
161 config.process_argparse_options(args) | |
162 self.assertIsNone(interface.state.flush_thread) | |
163 | |
164 @mock.patch('infra_libs.ts_mon.common.monitors.PubSubMonitor', autospec=True) | |
165 def test_pubsub_args(self, fake_monitor): | |
166 singleton = mock.Mock() | |
167 fake_monitor.return_value = singleton | |
168 p = argparse.ArgumentParser() | |
169 config.add_argparse_options(p) | |
170 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
171 '--ts-mon-endpoint', 'pubsub://mytopic/myproject']) | |
172 config.process_argparse_options(args) | |
173 fake_monitor.assert_called_once_with( | |
174 '/path/to/creds.p8.json', 'mytopic', 'myproject', | |
175 use_instrumented_http=True) | |
176 self.assertIs(interface.state.global_monitor, singleton) | |
177 | |
178 @mock.patch('infra_libs.ts_mon.common.monitors.PubSubMonitor', autospec=True) | |
179 def test_pubsub_without_credentials(self, fake_monitor): | |
180 # safety net, not supposed to be called. | |
181 singleton = mock.Mock() | |
182 fake_monitor.return_value = singleton | |
183 | |
184 p = argparse.ArgumentParser() | |
185 config.add_argparse_options(p) | |
186 args = p.parse_args(['--ts-mon-config-file', | |
187 os.path.join(DATA_DIR, 'empty-config-file.json'), | |
188 '--ts-mon-endpoint', 'pubsub://mytopic/myproject']) | |
189 config.process_argparse_options(args) | |
190 self.assertIsInstance(interface.state.global_monitor, monitors.NullMonitor) | |
191 | |
192 @mock.patch('infra_libs.ts_mon.common.monitors.DebugMonitor', auto_spec=True) | |
193 def test_dryrun_args(self, fake_monitor): | |
194 singleton = mock.Mock() | |
195 fake_monitor.return_value = singleton | |
196 p = argparse.ArgumentParser() | |
197 config.add_argparse_options(p) | |
198 args = p.parse_args(['--ts-mon-endpoint', 'file://foo.txt']) | |
199 config.process_argparse_options(args) | |
200 fake_monitor.assert_called_once_with('foo.txt') | |
201 self.assertIs(interface.state.global_monitor, singleton) | |
202 | |
203 def test_device_args(self): | |
204 p = argparse.ArgumentParser() | |
205 config.add_argparse_options(p) | |
206 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
207 '--ts-mon-target-type', 'device', | |
208 '--ts-mon-device-region', 'reg', | |
209 '--ts-mon-device-role', 'role', | |
210 '--ts-mon-device-network', 'net', | |
211 '--ts-mon-device-hostname', 'host']) | |
212 config.process_argparse_options(args) | |
213 self.assertEqual(interface.state.target.region, 'reg') | |
214 self.assertEqual(interface.state.target.role, 'role') | |
215 self.assertEqual(interface.state.target.network, 'net') | |
216 self.assertEqual(interface.state.target.hostname, 'host') | |
217 | |
218 def test_autogen_device_args(self): | |
219 p = argparse.ArgumentParser() | |
220 config.add_argparse_options(p) | |
221 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
222 '--ts-mon-target-type', 'device', | |
223 '--ts-mon-device-region', 'reg', | |
224 '--ts-mon-device-role', 'role', | |
225 '--ts-mon-device-network', 'net', | |
226 '--ts-mon-device-hostname', 'host', | |
227 '--ts-mon-autogen-hostname']) | |
228 config.process_argparse_options(args) | |
229 self.assertEqual(interface.state.target.region, 'reg') | |
230 self.assertEqual(interface.state.target.role, 'role') | |
231 self.assertEqual(interface.state.target.network, 'net') | |
232 self.assertEqual(interface.state.target.hostname, 'autogen:host') | |
233 | |
234 def test_autogen_device_config(self): | |
235 self.mock(config, 'load_machine_config', lambda x: { | |
236 'autogen_hostname': True, | |
237 'credentials': '/path/to/creds.p8.json', | |
238 'endpoint': 'test://endpoint'}) | |
239 p = argparse.ArgumentParser() | |
240 config.add_argparse_options(p) | |
241 args = p.parse_args([ | |
242 '--ts-mon-target-type', 'device', | |
243 '--ts-mon-device-region', 'reg', | |
244 '--ts-mon-device-role', 'role', | |
245 '--ts-mon-device-network', 'net', | |
246 '--ts-mon-device-hostname', 'host']) | |
247 config.process_argparse_options(args) | |
248 self.assertEqual(interface.state.target.region, 'reg') | |
249 self.assertEqual(interface.state.target.role, 'role') | |
250 self.assertEqual(interface.state.target.network, 'net') | |
251 self.assertEqual(interface.state.target.hostname, 'autogen:host') | |
252 | |
253 | |
254 def test_task_args(self): | |
255 p = argparse.ArgumentParser() | |
256 config.add_argparse_options(p) | |
257 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
258 '--ts-mon-target-type', 'task', | |
259 '--ts-mon-task-service-name', 'serv', | |
260 '--ts-mon-task-job-name', 'job', | |
261 '--ts-mon-task-region', 'reg', | |
262 '--ts-mon-task-hostname', 'host', | |
263 '--ts-mon-task-number', '1']) | |
264 config.process_argparse_options(args) | |
265 self.assertEqual(interface.state.target.service_name, 'serv') | |
266 self.assertEqual(interface.state.target.job_name, 'job') | |
267 self.assertEqual(interface.state.target.region, 'reg') | |
268 self.assertEqual(interface.state.target.hostname, 'host') | |
269 self.assertEqual(interface.state.target.task_num, 1) | |
270 | |
271 def test_autogen_task_args(self): | |
272 p = argparse.ArgumentParser() | |
273 config.add_argparse_options(p) | |
274 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
275 '--ts-mon-target-type', 'task', | |
276 '--ts-mon-task-service-name', 'serv', | |
277 '--ts-mon-task-job-name', 'job', | |
278 '--ts-mon-task-region', 'reg', | |
279 '--ts-mon-task-hostname', 'host', | |
280 '--ts-mon-task-number', '1', | |
281 '--ts-mon-autogen-hostname']) | |
282 config.process_argparse_options(args) | |
283 self.assertEqual(interface.state.target.service_name, 'serv') | |
284 self.assertEqual(interface.state.target.job_name, 'job') | |
285 self.assertEqual(interface.state.target.region, 'reg') | |
286 self.assertEqual(interface.state.target.hostname, 'autogen:host') | |
287 self.assertEqual(interface.state.target.task_num, 1) | |
288 | |
289 def test_autogen_task_config(self): | |
290 self.mock(config, 'load_machine_config', lambda x: { | |
291 'autogen_hostname': True, | |
292 'credentials': '/path/to/creds.p8.json', | |
293 'endpoint': 'test://endpoint'}) | |
294 p = argparse.ArgumentParser() | |
295 config.add_argparse_options(p) | |
296 args = p.parse_args(['--ts-mon-target-type', 'task', | |
297 '--ts-mon-task-service-name', 'serv', | |
298 '--ts-mon-task-job-name', 'job', | |
299 '--ts-mon-task-region', 'reg', | |
300 '--ts-mon-task-hostname', 'host', | |
301 '--ts-mon-task-number', '1']) | |
302 config.process_argparse_options(args) | |
303 self.assertEqual(interface.state.target.service_name, 'serv') | |
304 self.assertEqual(interface.state.target.job_name, 'job') | |
305 self.assertEqual(interface.state.target.region, 'reg') | |
306 self.assertEqual(interface.state.target.hostname, 'autogen:host') | |
307 self.assertEqual(interface.state.target.task_num, 1) | |
308 | |
309 def test_task_args_missing_service_name(self): | |
310 p = argparse.ArgumentParser() | |
311 config.add_argparse_options(p) | |
312 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
313 '--ts-mon-target-type', 'task', | |
314 '--ts-mon-task-job-name', 'job', | |
315 '--ts-mon-task-region', 'reg', | |
316 '--ts-mon-task-hostname', 'host', | |
317 '--ts-mon-task-number', '1']) | |
318 with self.assertRaises(SystemExit): | |
319 config.process_argparse_options(args) | |
320 | |
321 def test_task_args_missing_job_name(self): | |
322 p = argparse.ArgumentParser() | |
323 config.add_argparse_options(p) | |
324 args = p.parse_args(['--ts-mon-credentials', '/path/to/creds.p8.json', | |
325 '--ts-mon-target-type', 'task', | |
326 '--ts-mon-task-service-name', 'serv', | |
327 '--ts-mon-task-region', 'reg', | |
328 '--ts-mon-task-hostname', 'host', | |
329 '--ts-mon-task-number', '1']) | |
330 with self.assertRaises(SystemExit): | |
331 config.process_argparse_options(args) | |
332 | |
333 def test_metric_name_prefix(self): | |
334 p = argparse.ArgumentParser() | |
335 config.add_argparse_options(p) | |
336 args = p.parse_args(['--ts-mon-metric-name-prefix', '/test/random/']) | |
337 config.process_argparse_options(args) | |
338 self.assertEqual('/test/random/', interface.state.metric_name_prefix) | |
339 | |
340 @mock.patch('infra_libs.ts_mon.common.monitors.NullMonitor', autospec=True) | |
341 def test_no_args(self, fake_monitor): | |
342 singleton = mock.Mock() | |
343 fake_monitor.return_value = singleton | |
344 p = argparse.ArgumentParser() | |
345 config.add_argparse_options(p) | |
346 args = p.parse_args([]) | |
347 config.process_argparse_options(args) | |
348 self.assertEqual(1, len(fake_monitor.mock_calls)) | |
349 self.assertEqual('/chrome/infra/', interface.state.metric_name_prefix) | |
350 self.assertIs(interface.state.global_monitor, singleton) | |
351 | |
352 @mock.patch('requests.get', autospec=True) | |
353 def test_gce_region(self, mock_get): | |
354 r = mock_get.return_value | |
355 r.status_code = 200 | |
356 r.text = 'projects/182615506979/zones/us-central1-f' | |
357 | |
358 self.assertEquals('us-central1-f', config._default_region('foo.golo')) | |
359 | |
360 @mock.patch('requests.get', autospec=True) | |
361 def test_gce_region_timeout(self, mock_get): | |
362 mock_get.side_effect = requests.exceptions.Timeout | |
363 self.assertEquals('golo', config._default_region('foo.golo')) | |
364 | |
365 @mock.patch('requests.get', autospec=True) | |
366 def test_gce_region_404(self, mock_get): | |
367 r = mock_get.return_value | |
368 r.status_code = 404 | |
369 | |
370 self.assertEquals('golo', config._default_region('foo.golo')) | |
371 | |
372 | |
373 class ConfigTest(unittest.TestCase): | |
374 | |
375 def test_load_machine_config(self): | |
376 with infra_libs.temporary_directory() as temp_dir: | |
377 filename = os.path.join(temp_dir, 'config') | |
378 with open(filename, 'w') as fh: | |
379 json.dump({'foo': 'bar'}, fh) | |
380 | |
381 self.assertEquals({'foo': 'bar'}, config.load_machine_config(filename)) | |
382 | |
383 def test_load_machine_config_bad(self): | |
384 with infra_libs.temporary_directory() as temp_dir: | |
385 filename = os.path.join(temp_dir, 'config') | |
386 with open(filename, 'w') as fh: | |
387 fh.write('not a json file') | |
388 | |
389 with self.assertRaises(ValueError): | |
390 config.load_machine_config(filename) | |
391 | |
392 def test_load_machine_config_not_exists(self): | |
393 self.assertEquals({}, config.load_machine_config('does not exist')) | |
OLD | NEW |