| 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 |